AlgoInsight

Free lesson · Java Basic To Advance

Primitive Types

Easy8 min readjava

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:

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 L suffix on long literals. long bigNumber = 5_000_000_000; is a compile error because 5_000_000_000 is too large for an int. The fix is 5_000_000_000L. This catches many learners by surprise.

Assuming 0.1 + 0.2 == 0.3. It isn't. Floating-point arithmetic is approximate. Use BigDecimal for 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 or BigDecimal.

Confusing char and String. '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 byte as unsigned. byte is 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 do b & 0xFF to get the unsigned value as an int. 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 int and Integer?" leads to autoboxing discussion (Topic 2.3). "Why doesn't 0.1 + 0.2 == 0.3?" tests floating-point understanding. "What's the size of a long?" tests basic recall.

Topic 2.9 has the full interview treatment for the foundational syntax cluster.

Try It

Exercise: In your IDE, create a PrimitiveExperiments class with a main method. Try these:

  1. Print Integer.MAX_VALUE + 1. Note the result — overflow wraps around to the negative minimum.
  2. Print 0.1 + 0.2. See the imprecision.
  3. Print (int)('A' + 1) and (char)('A' + 1). See the difference between numeric and character interpretation.
  4. Try long big = 5_000_000_000; without the L suffix. Read the compile error.
  5. Print Double.MAX_VALUE and Double.MIN_VALUE. Note that MIN_VALUE is 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.

Back to Java Basic To Advance