Free lesson · Java Basic To Advance
Primitive Types
The Eight Building Blocks
Java has exactly eight primitive types. Every value in Java that isn't a reference to an object is one of these eight. Knowing them precisely — their sizes, their ranges, their default values, their quirks — is foundational. This is the kind of material that comes up in early interview screens because it filters out candidates who learned Java casually.
The eight primitives:
| Type | Size | Range | Default |
|---|---|---|---|
byte |
8 bits | -128 to 127 | 0 |
short |
16 bits | -32,768 to 32,767 | 0 |
int |
32 bits | ~-2.1 billion to ~2.1 billion | 0 |
long |
64 bits | ~-9.2 quintillion to ~9.2 quintillion | 0L |
float |
32 bits | ~±3.4 × 10³⁸ (6-7 decimal digits precision) | 0.0f |
double |
64 bits | ~±1.8 × 10³⁰⁸ (15-16 decimal digits precision) | 0.0 |
char |
16 bits | 0 to 65,535 (Unicode characters) | '\u0000' |
boolean |
JVM-defined (typically 1 bit logically, 32 bits in practice) | true or false | false |
Memorize the sizes of the four most common: int is 32 bits, long is 64 bits, double is 64 bits, boolean is true/false. The rest you can look up — but knowing the common ones cold is expected at interview time.
Integer Types: byte, short, int, long
Java has four integer types of different sizes. They all hold signed (positive or negative) whole numbers.
int is the default. Use int for almost all integer needs. It's 32 bits, holding values from approximately -2.1 billion to +2.1 billion. This is plenty of range for most counters, indices, sizes, and IDs.
int count = 0;
int yearOfBirth = 1991;
int largeNumber = 2_000_000_000; // underscores allowed for readability
The underscore separators (2_000_000_000) are a Java 7+ feature purely for readability. The compiler ignores them. Use them in long literals to make values easier to scan.
long for very large numbers. When you need values larger than ~2 billion (transaction IDs, timestamps in milliseconds, file sizes, populations), use long. The literal needs an L suffix to tell the compiler it's a long, not an int:
long worldPopulation = 8_100_000_000L; // 8.1 billion
long milliseconds = System.currentTimeMillis(); // returns long
long fileSize = 10_000_000_000L; // 10 GB in bytes
Without the L suffix, 8_100_000_000 would be treated as an int literal — which overflows the int range and produces a compile error. The lowercase l works too but looks too much like the digit 1, so use uppercase L.
byte and short for memory-constrained scenarios. These are rarely used in modern application code. They exist mainly for:
- Reading binary data (
byteis common in file I/O and networking) - Memory-sensitive scenarios (large arrays of small numbers)
- Interoperating with APIs that require specific sizes
For typical business logic, prefer int. Premature use of byte or short to "save memory" usually doesn't help and adds complexity.
Interactive animation: The declaration is fine, the literal is not - 5_000_000_000 is an int until the L suffix makes it a long.
Floating-Point Types: float and double
Two floating-point types, both following IEEE 754 standard:
double is the default for decimals. 64 bits, ~15-16 decimal digits of precision. Use double for almost all floating-point needs.
double pi = 3.14159265358979;
double temperature = 98.6;
double avogadro = 6.022e23; // scientific notation
float for memory-constrained scenarios. 32 bits, ~6-7 decimal digits of precision. Requires an f suffix:
float small = 3.14f;
// float invalid = 3.14; // compile error — 3.14 is a double literal
In modern Java, float is mostly used for graphics code or where you have huge arrays of floating-point numbers. Almost everything else should use double.
Critical pitfall: floating-point arithmetic isn't exact. This is a frequent interview question:
double result = 0.1 + 0.2;
System.out.println(result); // 0.30000000000000004
System.out.println(result == 0.3); // false!
The values 0.1 and 0.2 cannot be represented exactly in binary floating-point. The result is a tiny bit off from 0.3. This is true in every language using IEEE 754, not a Java quirk.
For financial calculations or anywhere exact decimal arithmetic matters, use BigDecimal (a reference type, covered in later modules) instead of double. For "is this number approximately equal?" comparisons, check whether the difference is within an acceptable epsilon:
double a = 0.1 + 0.2;
double b = 0.3;
if (Math.abs(a - b) < 0.000001) {
System.out.println("Approximately equal");
}
Interactive animation: 0.1 + 0.2 prints 0.30000000000000004 and == 0.3 is false - an IEEE 754 fact, not a Java quirk.
The Character Type: char
char represents a single Unicode character. Internally, it's a 16-bit unsigned integer storing the character's code point.
char letter = 'A';
char digit = '7';
char unicode = '\u00E9'; // é (lowercase e with acute accent)
char chinese = '中';
Single quotes for char literals. Double quotes are for String. This distinction trips up beginners — 'A' is a char, "A" is a String, and they're not interchangeable.
A subtle but important fact: char is numerically a 16-bit unsigned integer. You can do arithmetic with it:
char a = 'A'; // 65 in Unicode/ASCII
char b = 'B';
int diff = b - a; // 1
char shifted = (char)(a + 1); // 'B'
This is the basis for many string manipulation algorithms (sorting characters, comparing alphabetically, etc.). When you see char c = (char)(letter + 32) in code, it's converting uppercase to lowercase via numeric arithmetic on the Unicode value.
Java 16 limitation: char only covers the Basic Multilingual Plane. Most Unicode characters fit in 16 bits, but some (emojis, some less-common scripts) require 21 bits and are encoded as "surrogate pairs" — two char values. For full Unicode support, use the String and Character methods that handle code points correctly.
Interactive animation: char is a number - 'B' minus 'A' is 1, and (char)(a + 1) gives 'B'.
The Boolean Type: boolean
boolean holds either true or false. No other values:
boolean isReady = true;
boolean isComplete = false;
// boolean x = 0; // compile error — Java is strict
// boolean y = "true"; // compile error
In some languages (C, JavaScript), zero is falsy and non-zero is truthy. Java doesn't allow this implicit conversion. if (count) doesn't compile if count is an int. You have to write if (count != 0). This explicitness prevents a class of bugs common in those other languages.
The JVM specification leaves boolean storage flexible. Most implementations use 32 bits for a single boolean (CPU alignment), but boolean[] arrays may be stored as packed bits. You don't need to worry about this for typical code.
Interactive animation: No truthiness in Java - boolean x = 0 and if (count) will not compile, so you write count != 0.
Default Values: A Field-by-Field Reference
When a primitive is used as an instance variable (field) without explicit initialization, it gets a default value:
public class Defaults {
byte b; // 0
short s; // 0
int i; // 0
long l; // 0L
float f; // 0.0f
double d; // 0.0
char c; // '\u0000' (null character)
boolean bool; // false
}
Local variables (declared inside methods) don't get defaults — the compiler requires explicit initialization before use. This is an intentional safety feature.
Literals and Number Bases
Java supports literals in multiple bases:
int decimal = 42;
int binary = 0b101010; // 42 in binary (Java 7+)
int octal = 052; // 42 in octal (leading 0)
int hex = 0x2A; // 42 in hexadecimal
long bigNumber = 9_223_372_036_854_775_807L; // max long, with separators
float gpa = 3.7f;
double avogadro = 6.022e23; // scientific notation
char tab = '\t'; // escape sequence
Common escape sequences for char and String:
| Escape | Meaning |
|---|---|
\n |
Newline |
\t |
Tab |
\r |
Carriage return |
\\ |
Backslash |
\' |
Single quote |
\" |
Double quote |
\u#### |
Unicode code point |
\0 |
Null character |
graph TD
A[Primitive Types] --> B[Integer]
A --> C[Floating-point]
A --> D[Other]
B --> B1[byte 8-bit]
B --> B2[short 16-bit]
B --> B3[int 32-bit DEFAULT]
B --> B4[long 64-bit]
C --> C1[float 32-bit]
C --> C2[double 64-bit DEFAULT]
D --> D1[char 16-bit Unicode]
D --> D2[boolean true/false]
style B3 fill:#10b981,color:#fff
style C2 fill:#10b981,color:#fff
This diagram organizes Java's eight primitive types into three categories. Integer types have four variants of increasing size — byte at 8 bits, short at 16 bits, int at 32 bits which is the default, and long at 64 bits. Floating-point types have two variants — float at 32 bits and double at 64 bits which is the default. The remaining two primitives are char, which is 16 bits and represents Unicode characters, and boolean, which holds true or false. For most code, int is the default integer type and double is the default decimal type — the other sizes are for specific needs.
Performance Considerations
A note on performance, since this is a senior-interview topic:
Primitives are faster than their wrapper types. Each primitive has a corresponding wrapper class (int ↔ Integer, double ↔ Double, etc., covered in Topic 2.3). Primitives are stored directly in memory and operated on by CPU instructions. Wrappers involve object allocation and pointer indirection.
For hot code paths processing many numbers, prefer primitives. For collections (which can't hold primitives directly), the JVM does autoboxing automatically, but it has performance cost.
int arithmetic is faster than long. On 64-bit hardware, both are fast, but int operations are sometimes slightly faster due to register allocation and SIMD optimization. For counter variables and array indices, prefer int unless you genuinely need the range.
double is faster than BigDecimal by orders of magnitude. BigDecimal is exact but allocates objects for every operation. For non-financial work, double is the right default.
These performance gaps matter mainly in inner loops processing millions of values. For typical application code, choose primitives based on semantic clarity, not performance.
Common Pitfalls
Warning: Forgetting the
Lsuffix on long literals.long bigNumber = 5_000_000_000;is a compile error because5_000_000_000is too large for anint. The fix is5_000_000_000L. This catches many learners by surprise.Assuming
0.1 + 0.2 == 0.3. It isn't. Floating-point arithmetic is approximate. UseBigDecimalfor exact decimal math or compare with epsilon for approximate equality.Using
==for floating-point equality. Same root cause as above. The result depends on tiny rounding differences. Always use epsilon comparison orBigDecimal.Confusing
charandString.'A'and"A"are different. The first is a 16-bit primitive; the second is a String object. Some operations (like concatenation) work with both because Java does implicit conversions, but the distinction matters for method signatures and storage.Treating
byteas unsigned.byteis signed in Java, range -128 to 127. If you read a byte from a stream and want to treat it as 0-255, you have to dob & 0xFFto get the unsigned value as anint. This bites many people doing file or network I/O.
Interactive animation: byte is signed, so a value above 127 arrives negative - b & 0xFF recovers the unsigned value.
Why This Matters in Interviews
Interview: Primitive questions are common in early screens and phone interviews. "What are Java's primitive types?" expects you to list all eight with their sizes. "What's the difference between
intandInteger?" leads to autoboxing discussion (Topic 2.3). "Why doesn't0.1 + 0.2 == 0.3?" tests floating-point understanding. "What's the size of along?" tests basic recall.Topic 2.9 has the full interview treatment for the foundational syntax cluster.
Try It
Exercise: In your IDE, create a
PrimitiveExperimentsclass with amainmethod. Try these:
Integer.MAX_VALUE + 1. Note the result — overflow wraps around to the negative minimum.0.1 + 0.2. See the imprecision.(int)('A' + 1)and(char)('A' + 1). See the difference between numeric and character interpretation.- Try
long big = 5_000_000_000;without theLsuffix. Read the compile error.Double.MAX_VALUEandDouble.MIN_VALUE. Note thatMIN_VALUEis the smallest positive value, not the most negative.Each surprise here teaches a real concept. The overflow behavior, the floating-point imprecision, the char-as-integer trick — all show up in interview questions and production bugs.