Java has exactly 8 primitive types with fixed sizes on every platform; everything else is a reference to an object.
The 8 primitives
| Type | Size | Range / values | Default | Literal |
|---|---|---|---|---|
byte | 8 bit | −128 … 127 | 0 | (byte) 10 |
short | 16 bit | −32,768 … 32,767 | 0 | (short) 10 |
int | 32 bit | −2³¹ … 2³¹−1 (≈ ±2.1 billion) | 0 | 42, 0x2A, 0b101010, 1_000_000 |
long | 64 bit | −2⁶³ … 2⁶³−1 (≈ ±9.2 × 10¹⁸) | 0L | 42L |
float | 32 bit | IEEE 754, ~7 significant digits | 0.0f | 3.14f |
double | 64 bit | IEEE 754, ~15–16 significant digits | 0.0d | 3.14, 1e-9 |
char | 16 bit | UTF-16 code unit '\u0000' … '\uffff' (unsigned) | '\u0000' | 'A', '\n', '\u0041' |
boolean | JVM-dependent | true / false (not 0/1!) | false | true |
public class Main {
public static void main(String[] args) {
System.out.println(Byte.MIN_VALUE + " " + Byte.MAX_VALUE);
System.out.println(Integer.MAX_VALUE + " " + Long.MAX_VALUE);
System.out.println((int) Character.MAX_VALUE + " " + Character.SIZE + " bits");
int million = 1_000_000; // underscores for readability
System.out.println(million + " " + 0xFF + " " + 0b1010 + " " + 017);
char c = 'A';
System.out.println(c + 1); // char promoted to int
System.out.println((char) (c + 1));
}
}-128 127
2147483647 9223372036854775807
65535 16 bits
1000000 255 10 15
66
BVariables: local, instance, static
| Kind | Declared | Lives in | Default value? |
|---|---|---|---|
| Local | Inside a method/block | Stack frame | No — must be assigned before use (compile error otherwise) |
| Instance (field) | In the class, no static | Inside each object on the heap | Yes (0, false, null) |
| Static (class variable) | static in the class | Once per class | Yes |
public class Main {
public static void main(String[] args) {
int x;
System.out.println(x); // local variable never assigned
}
}Main.java:4: error: variable x might not have been initialized
System.out.println(x); // local variable never assigned
^
1 errorvar — local type inference (Java 10+)
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var count = 10; // int
var price = 9.99; // double
var names = new ArrayList<String>(); // ArrayList<String>
names.add("Ada");
for (var n : names) System.out.println(n + " " + count + " " + price);
}
}Ada 10 9.99Still static typing — the compiler infers the type once; it can't change later.
Only for local variables with an initialiser (and loop variables). Not for fields, parameters or return types.
var x = null;andvar a = {1, 2};don't compile — there's nothing to infer from.
Integer overflow & floating-point surprises
public class Main {
public static void main(String[] args) {
int big = Integer.MAX_VALUE;
System.out.println(big + 1); // wraps around silently
long ok = big + 1L; // do the math in long
System.out.println(ok);
System.out.println(1_000_000 * 1_000_000); // int * int overflows
System.out.println(1_000_000L * 1_000_000);
try {
Math.addExact(big, 1);
} catch (ArithmeticException e) {
System.out.println("addExact: " + e.getMessage());
}
System.out.println(0.1 + 0.2);
System.out.println(0.1f + 0.2f);
System.out.println(1.0 / 0 + " " + -1.0 / 0 + " " + 0.0 / 0);
}
}-2147483648
2147483648
-727379968
1000000000000
addExact: integer overflow
0.30000000000000004
0.3
Infinity -Infinity NaNimport java.math.BigDecimal;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) {
System.out.println(new BigDecimal("0.1").add(new BigDecimal("0.2")));
System.out.println(new BigDecimal(0.1)); // the double's exact binary value!
BigInteger f = BigInteger.ONE;
for (int i = 2; i <= 25; i++) f = f.multiply(BigInteger.valueOf(i));
System.out.println("25! = " + f);
}
}0.3
0.1000000000000000055511151231257827021181583404541015625
25! = 15511210043330985984000000Why is char 16 bits in Java?
What are default values, and do local variables get them?
Does var make Java dynamically typed?