1.1 Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting
Key Takeaways
Java defines eight primitive types: byte, short, int, long, float, double, char, and boolean; member fields receive default zero-equivalent values, whereas local variables must be explicitly initialized prior to access.
Numeric literal representations include binary (0b), octal (0), and hexadecimal (0x); underscores are permitted strictly between digits and never adjacent to prefixes, decimal points, or type suffixes.
Primitive wrapper classes (Byte, Short, Integer, Long, Character, Boolean) cache immutable instances across standardized ranges (-128 to 127 for integers); comparison with reference equality (==) outside these bounds fails.
Binary arithmetic operations automatically promote any operand smaller than int (byte, short, char) to int before evaluation, requiring explicit casts to assign results back to narrower types unless evaluating compile-time constant expressions.
Integer overflow and underflow wrap silently across two's complement boundary limits without throwing runtime exceptions; widening conversions occur implicitly, whereas narrowing conversions require explicit casting.
Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting
Understanding Java's fundamental data representations requires mastering primitive types, numeric literal syntaxes, wrapper class caching, and arithmetic promotion rules. Professional Java certification exams frequently test edge cases in type conversion, literal formatting, and wrapper identity.
The Eight Primitive Data Types
Java provides eight built-in primitive types divided into four categories: integers, floating-point numbers, characters, and booleans. Primitive values reside directly in stack memory when declared as local variables or embedded within object layouts on the heap when declared as instance fields.
| Type | Size | Range | Wrapper Class | Default Value (Fields Only) |
|---|---|---|---|---|
byte | 8 bits (1 byte) | -128 to 127 ( to ) | java.lang.Byte | 0 |
short | 16 bits (2 bytes) | -32,768 to 32,767 ( to ) | java.lang.Short | 0 |
int | 32 bits (4 bytes) | -2,147,483,648 to 2,147,483,647 ( to ) | java.lang.Integer | 0 |
long | 64 bits (8 bytes) | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | java.lang.Long | 0L |
float | 32 bits (4 bytes) | IEEE 754 floating point (approx. to ) | java.lang.Float | 0.0f |
double | 64 bits (8 bytes) | IEEE 754 floating point (approx. to ) | java.lang.Double | 0.0d |
char | 16 bits (2 bytes) | 0 to 65,535 unsigned ('\u0000' to '\uffff') | java.lang.Character | '\u0000' (null character) |
boolean | JVM-dependent | true or false | java.lang.Boolean | false |
Warning
Field Defaults vs. Local Variable Initialization
Only instance and static fields receive automatic default values during class loading or object instantiation. Local variables declared inside method bodies, constructor bodies, or initializer blocks receive no default value. Attempting to read a local variable before it is definitively assigned results in a compile-time error: variable x might not have been initialized.
public class InitializationDemo {
int instanceCount; // Defaults to 0
boolean active; // Defaults to false
public void compute() {
int localSum; // Uninitialized
// System.out.println(localSum); // COMPILE ERROR: localSum might not have been initialized
localSum = 10;
System.out.println(localSum); // Compiles successfully: prints 10
}
}
Literal Formats and Numeric Notations
Integral literals default to int unless suffixed with uppercase L or lowercase l (always use L for readability). Floating-point literals default to double unless suffixed with F or f (D or d is optional for double).
Radix Prefixes
Java supports four number systems for integer literals:
- Decimal (base 10): Standard digits
0–9without leading zeros (e.g.,42). - Hexadecimal (base 16): Prefixed with
0xor0X, digits0–9andA–F(case-insensitive, e.g.,0x2Ais decimal 42). - Binary (base 2): Prefixed with
0bor0B, digits0and1(e.g.,0b101010is decimal 42). - Octal (base 8): Prefixed with a single leading
0, digits0–7(e.g.,052is decimal 42).
Warning
The Octal Trap
Any integer literal starting with 0 is interpreted as octal. Using digits 8 or 9 in an octal literal causes a compiler error: integer number too large: 089 (or digit '8' out of range). Always watch for leading zeros in test questions!
Underscore Placement Rules
Underscores (_) can be inserted between digits to enhance readability in large numeric literals. However, strict placement constraints apply:
- Allowed: Strictly between adjacent digits (e.g.,
1_000_000,0b1011_0100,0xFF_EC_01). - Prohibited:
- At the very beginning or end of a literal:
_100(treated as identifier),100_(compile error). - Adjacent to a decimal point:
3._1415or3_.1415(compile error). - Adjacent to radix prefixes:
0x_FF,0_xFF,0b_1010(compile error). - Adjacent to type suffixes:
1000_L,4.5_F,99.9_D(compile error).
- At the very beginning or end of a literal:
int validDec = 1_000_000; // Valid
int validHex = 0xCAFE_BABE; // Valid
long validBin = 0b1101_0010_1001L; // Valid
// int err1 = 0x_7F; // COMPILE ERROR: cannot put underscore after 0x
// double err2 = 12_.5; // COMPILE ERROR: cannot put underscore before decimal point
// float err3 = 100_f; // COMPILE ERROR: cannot put underscore before 'f' suffix
Wrapper Classes, Autoboxing, and Value Caching
Each primitive type has a corresponding wrapper class in java.lang. Modern Java provides automatic conversion between primitives and wrappers:
- Autoboxing: Automatic conversion of a primitive to its corresponding wrapper object (e.g.,
Integer num = 42;). - Unboxing: Automatic extraction of the primitive value from a wrapper object (e.g.,
int val = num;).
Integer boxed = 100; // Autoboxing via Integer.valueOf(100)
int unboxed = boxed; // Unboxing via boxed.intValue()
Integer nullRef = null;
// int failedUnbox = nullRef; // Compiles, but throws NullPointerException at runtime!
The Flyweight Value Cache
To conserve memory and boost performance, the JVM maintains an internal cache of pre-allocated wrapper instances. When autoboxing occurs or when calling valueOf(), the JVM returns a reference to a cached instance for values within the following boundaries:
Byte,Short,Integer,Long: -128 through 127 (inclusive).Character: 0 through 127 ('\u0000'through'\u007F').Boolean:Boolean.TRUEandBoolean.FALSE.FloatandDouble: No caching (infinite floating-point representations).
Because wrapper objects are reference types, the == operator compares object identity (heap memory addresses), whereas .equals() compares wrapped primitive values:
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (both point to the cached flyweight instance)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (values outside cache allocate new heap objects)
System.out.println(c.equals(d)); // true (compares internal int value: 128 == 128)
Note
Constructors for all primitive wrappers (e.g., new Integer(10)) were deprecated in Java 9 and marked for removal in Java 16 (JEP 390) because they bypass caching and allocate redundant heap objects. In Java 17 they still compile, but with a removal warning. Always prefer autoboxing or static factory methods such as Integer.valueOf(10).
Type Promotion and Casting Rules
Java enforces strict binary numeric promotion rules for arithmetic expressions (+, -, *, /, %). The operands are widened according to the following precedence order:
- If either operand is
double, the other is converted todouble. - Otherwise, if either operand is
float, the other is converted tofloat. - Otherwise, if either operand is
long, the other is converted tolong. - Otherwise, BOTH operands are converted to
int, even if neither was originally anint!
byte b1 = 10;
byte b2 = 20;
// byte b3 = b1 + b2; // COMPILE ERROR: b1 + b2 evaluates to int; cannot assign int to byte
byte b3 = (byte)(b1 + b2); // Explicit cast required
Compile-Time Constant Inlining
An exception to mandatory narrowing casts occurs with compile-time constant expressions. When the compiler can evaluate an expression at compile time and the resulting value falls within the range of the target smaller integer type (byte, short, char), the assignment is permitted without an explicit cast:
final byte f1 = 20;
final byte f2 = 30;
byte f3 = f1 + f2; // Compiles! Evaluated at compile time as 50, fitting into byte
final int bigConst = 1000;
// byte f4 = bigConst; // COMPILE ERROR: 1000 exceeds byte range (-128 to 127)
Widening vs. Narrowing and Two's Complement Overflow
Widening conversions (e.g., byte -> short -> int -> long -> float -> double) happen automatically without data loss of magnitude (except potential least-significant-digit precision loss when converting int to float, or long to float or double). Narrowing conversions truncate higher-order bits and wrap around two's complement boundaries without throwing exceptions:
int high = 130;
byte narrowed = (byte) high;
System.out.println(narrowed); // Prints -126 (binary 00000000_00000000_00000000_10000010 truncated to 10000010 = -126)
int max = Integer.MAX_VALUE; // 2,147,483,647
System.out.println(max + 1); // Prints -2,147,483,648 (silent overflow to Integer.MIN_VALUE)
Finally, boolean is entirely incompatible with numeric types: it cannot be cast to or from any integer or floating-point type, neither implicitly nor explicitly ((int) true is a compile error).
Which of the following numeric literal declarations compiles successfully without any compiler errors?
int oct = 089;
long b = 0b1011_0100L;
float f = 3.14_f;
double total = 1_000_.0;
Consider the following code snippet:
final byte a = 40;
byte b = 50;
byte c = a + 10;
byte d = b + 10;
System.out.println(c + " " + d);
What is the result of attempting to compile and run this code?
Throws a ClassCastException at runtime
Outputs 50 60
Compilation fails on the assignment to d (byte d = b + 10;)
Compilation fails on the assignment to c (byte c = a + 10;)
What is the output of the following code snippet?
Integer x = 127;
Integer y = 127;
Integer m = 128;
Integer n = 128;
System.out.print((x == y) + " ");
System.out.print((m == n) + " ");
System.out.print(m.equals(n));
true false true
true true true
false false false
false false true
Sections you finish are checked off in the contents.