Java data types

Every variable in Java has a type. Types fall into two broad groups:
1. Primitives (stored directly on the stack or inside objects)
2. Reference types (variables hold a reference/pointer to an object on the heap).

Primitive types (always on stack)

Language provides these. They cannot be null.


Type     | Size (bytes) | Range / values
---------|--------------|------------------------------------------
byte     | 1 (signed)   | -128 to 127
short    | 2 (signed)   | -32,768 to 32,767
int      | 4 (signed)   | -2^31 to 2^31 - 1  (~±2.1 billion)
long     | 8 (signed)   | -2^63 to 2^63 - 1
float    | 4 (IEEE 754) | ~±3.4 × 10^38  (6–7 decimal digits)
double   | 8 (IEEE 754) | ~±1.7 × 10^308 (15 decimal digits)
boolean  | JVM-defined  | true or false only
char     | 2 (UTF-16)   | '\u0000' to '\uffff'  (single Unicode code unit)
      

Reference Variables

String, arrays, classes you define, enums, records, interfaces, and everything from the JDK (List, LocalDate, etc.). They can be null and are garbage-collected on the heap. See Garbage Collection.

String

String is a final class in java.lang, not a primitive. String literals are immutable — any method that "changes" a string returns a new object.


String a = "test";
String b = "test1";

a.length();              // 4
a.compareTo(b);          // negative (a comes before b lexicographically)
a.equals(b);             // false
a.equalsIgnoreCase("TEST"); // true

System.out.println(a.toUpperCase());   // TEST
System.out.println(a.substring(1, 3)); // es
      

Wrapper classes (Always allocated on heap)

A wrapper class is a class that encapsulates (wraps) a primitive data type into an object.
Every primitive type in Java has a corresponding wrapper class in the java.lang package (e.g., int becomes Integer, double becomes Double, char becomes Character).
Why Primitives types are wrapped in Objects?   By wrapping a primitive inside an object, it gains object-like capabilities, such as having methods, holding null values.
  Java collections (like ArrayList, HashMap, etc.) and generics only work with objects, not primitives. You cannot write ArrayList<int>, but you can write ArrayList<Integer>.

Arrays

Arrays are reference types that hold a fixed number of elements of the same type. Length is set at creation and cannot grow.


int[] nums = { 1, 2, 3, 4, 5 };
String[] names = new String[3];

names[0] = "Alice";
names[1] = "Bob";

System.out.println(nums.length);   // 5
System.out.println(nums[2]);       // 3

// Multi-dimensional
int[][] matrix = { { 1, 2 }, { 3, 4 } };
      

Classes & Objects

Objects generally lie on heap but not all.
JVM uses Escape Analysis to keep some Objects on stack


Enums

Enums define a fixed set of named constants. They are type-safe alternatives to integer or string constants.


enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

Day today = Day.MON;
Day tomorrow = Day.valueOf("TUE");

if (today == Day.MON) {
    System.out.println("Start of week");
}

for (Day d : Day.values()) {
    System.out.println(d);
}
      

Records (Java 16+)

Records are compact, immutable data carriers. The compiler generates constructor, accessors, equals, hashCode, and toString automatically.


record Point(int x, int y) {}

Point origin = new Point(0, 0);
Point p = new Point(3, 4);

System.out.println(p.x());          // 3  (accessor, not getX())
System.out.println(p);              // Point[x=3, y=4]
      

Common JDK types

Beyond collections, the JDK provides specialized reference types for math, time, and optional values.


Type            | Package          | Typical use
----------------|------------------|----------------------------------
BigInteger      | java.math        | Arbitrary-precision integers
BigDecimal      | java.math        | Exact decimal arithmetic (money)
LocalDate       | java.time        | Date without time zone (2026-07-18)
LocalDateTime   | java.time        | Date + time without zone
Instant         | java.time        | UTC timestamp (epoch-based)
ZonedDateTime   | java.time        | Date-time with time zone
UUID            | java.util        | 128-bit unique identifier
Optional<T>     | java.util        | Explicit nullable wrapper
Pattern         | java.util.regex  | Compiled regular expression
StringBuilder   | java.lang        | Mutable string builder
      

Special cases

void — not a variable type. Used only as a method return type meaning "returns nothing".


public void printHello() {
    System.out.println("Hello");
}
      

null — the default value for uninitialized reference-type fields. Assigning null to a primitive is a compile error.


String s = null;    // OK — reference type
// int n = null;    // compile error — primitive
      

var (Java 10+) — local type inference. The compiler deduces the type; it is not a new datatype.


var message = "Hello";           // inferred as String
var numbers = List.of(1, 2, 3);  // inferred as List<Integer>
      

Generics — parameterized types such as List<T> and Map<K, V> let collections and classes work with type-safe element types at compile time.