Hero Background

Next-Gen App & Browser Testing Cloud

Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Next-Gen App & Browser Testing Cloud

What Are Primitive Data Types in Java?

Java has 8 primitive data types — byte, short, int, long, float, double, char, and boolean. Unlike objects, primitives store their actual value directly in memory rather than a reference to an object. They are the building blocks of every Java program: four integer types, two floating-point types, one character type, and one boolean type. Each has a fixed size, a defined range of values, and a default value, which makes them fast, predictable, and memory-efficient compared with reference (non-primitive) types like String or arrays.

Below, we cover every primitive type with its size and range, runnable code for each, how primitives differ from reference types, wrapper classes and autoboxing, type casting, and the mistakes that trip up most developers — all written for testers and automation engineers who work with WebDriver.

What Are Primitive Data Types?

A primitive data type is a predefined data type built into the Java language that stores a single, simple value directly in memory. Primitives are not objects — they have no methods, cannot be null, and hold their value (a number, a character, or a true/false flag) rather than a reference pointing to an object on the heap. Because the size of each primitive is fixed by the language specification, the compiler knows exactly how much memory to allocate, which makes primitives fast and lightweight.

Java is a statically typed language, so every variable must declare its type before use. The eight primitives fall into four groups:

  • Integer typesbyte, short, int, and long store whole numbers of increasing size.
  • Floating-point typesfloat and double store numbers with a fractional part.
  • Character typechar stores a single 16-bit Unicode character.
  • Boolean typeboolean stores only true or false.

The 8 Java Primitive Data Types

The list below covers every Java primitive with its memory size, the range of values it can hold, its default value (for class fields), and a quick example. These sizes are guaranteed by the Java Language Specification and do not change across platforms — a key reason Java code behaves consistently everywhere.

  • byte: 8 bits (1 byte); range -128 to 127; default 0; example byte b = 100;
  • short: 16 bits (2 bytes); range -32,768 to 32,767; default 0; example short s = 20000;
  • int: 32 bits (4 bytes); range -2,147,483,648 to 2,147,483,647; default 0; example int i = 100000;
  • long: 64 bits (8 bytes); range -9.2 x 10^18 to 9.2 x 10^18; default 0L; example long l = 9000000000L;
  • float: 32 bits (4 bytes); range ~6-7 significant decimal digits; default 0.0f; example float f = 3.14f;
  • double: 64 bits (8 bytes); range ~15-16 significant decimal digits; default 0.0d; example double d = 3.14159;
  • char: 16 bits (2 bytes); range 0 to 65,535 (Unicode characters); default '\u0000'; example char c = 'A';
  • boolean: 1 bit (JVM-dependent); values true or false; default false; example boolean flag = true;

Note the literal suffixes: a long literal ends in L, a float literal ends in f, and a double literal can optionally end in d. Forgetting the L or f suffix is one of the most common compile errors for beginners.

Code Examples for Each Type

The snippet below declares and initializes every primitive type, then prints each value. Copy it into a Main class and run it to see the eight primitives in action.

public class PrimitivesDemo {
    public static void main(String[] args) {
        // Integer types
        byte  smallNumber = 100;          // -128 to 127
        short mediumNumber = 20000;       // -32,768 to 32,767
        int   regularNumber = 100000;     // most common integer type
        long  bigNumber = 9000000000L;    // note the L suffix

        // Floating-point types
        float  pi = 3.14f;                // note the f suffix
        double precisePi = 3.141592653589793;

        // Character type (single quotes, one character)
        char grade = 'A';

        // Boolean type
        boolean isJavaFun = true;

        System.out.println("byte:    " + smallNumber);
        System.out.println("short:   " + mediumNumber);
        System.out.println("int:     " + regularNumber);
        System.out.println("long:    " + bigNumber);
        System.out.println("float:   " + pi);
        System.out.println("double:  " + precisePi);
        System.out.println("char:    " + grade);
        System.out.println("boolean: " + isJavaFun);
    }
}

A few details worth noting: char uses single quotes (double quotes create a String), and because a char is internally a number, char letter = 65; would also produce 'A'. Each primitive can be combined in arithmetic, but mixing types triggers automatic type promotion, which we cover under type casting below.

Primitive vs Reference (Non-Primitive) Types

Everything in Java that is not one of the eight primitives is a reference (non-primitive) type — classes, interfaces, arrays, and enums. A reference variable stores the memory address of an object on the heap, not the object itself. The list below contrasts the two:

  • Stores: Primitive — the actual value; Reference — a reference (address) to an object.
  • Examples: Primitive — int, double, char, boolean; Reference — String, Integer, arrays, custom classes.
  • Can be null?: Primitive — No; Reference — Yes.
  • Has methods?: Primitive — No; Reference — Yes (e.g., str.length()).
  • Default value: Primitive — 0, 0.0, false, or '\u0000'; Reference — null.
  • Memory: Primitive — stored on the stack (for locals); Reference — object on the heap, reference on the stack.
  • Comparison: Primitive — use == to compare values; Reference — use .equals() to compare contents.

This distinction matters in real test code: comparing two String objects with == checks whether they are the same object, not whether they contain the same text. For value comparison you must call .equals() — a classic source of flaky assertions in automation suites.

Wrapper Classes and Autoboxing

Each primitive has a matching wrapper class in the java.lang package that lets you treat the value as an object: Byte, Short, Integer, Long, Float, Double, Character, and Boolean. Wrappers are essential when you need to store values in collections (which only hold objects), allow null, or call utility methods like Integer.parseInt().

Autoboxing is the automatic conversion of a primitive to its wrapper, and unboxing is the reverse. The compiler inserts these conversions for you:

import java.util.ArrayList;
import java.util.List;

public class BoxingDemo {
    public static void main(String[] args) {
        // Autoboxing: int -> Integer happens automatically
        Integer boxed = 42;

        // Unboxing: Integer -> int happens automatically
        int unboxed = boxed;

        // Collections only store objects, so autoboxing is implicit
        List<Integer> numbers = new ArrayList<>();
        numbers.add(10);   // int 10 autoboxed to Integer
        int first = numbers.get(0); // Integer unboxed back to int

        // Wrapper utility methods
        int parsed = Integer.parseInt("123");
        System.out.println(boxed + ", " + unboxed + ", " + first + ", " + parsed);
    }
}

Be careful: unboxing a null wrapper throws a NullPointerException. If an Integer is null and you assign it to an int, the JVM tries to unbox null and crashes at runtime.

Type Casting (Widening vs Narrowing)

Type casting converts a value of one primitive type into another. Java distinguishes two directions:

  • Widening (implicit) casting — a smaller type is converted to a larger one automatically and without data loss: byte → short → int → long → float → double.
  • Narrowing (explicit) casting — a larger type is converted to a smaller one. You must write the target type in parentheses, because the conversion can lose data or precision.
public class CastingDemo {
    public static void main(String[] args) {
        // Widening: automatic, no data loss
        int myInt = 9;
        double myDouble = myInt;   // int -> double (9 becomes 9.0)
        System.out.println("Widening: " + myDouble);

        // Narrowing: explicit cast required, may lose data
        double price = 9.99;
        int wholePrice = (int) price;  // double -> int (truncates to 9)
        System.out.println("Narrowing: " + wholePrice);

        // Narrowing can overflow silently
        int big = 300;
        byte small = (byte) big;   // 300 wraps around to 44
        System.out.println("Overflow: " + small);
    }
}

Narrowing a double to an int truncates the fractional part rather than rounding — 9.99 becomes 9, not 10. Casting a value that exceeds the target range (like 300 into a byte) silently wraps around, which is a frequent source of subtle bugs.

Signed vs Unsigned and Type Limits

A detail that surprises developers from C or C++: in Java the four integer types — byte, short, int, and long — are always signed two's complement, so they can hold negative values, and there is no unsigned keyword. The only unsigned primitive is char, whose range runs from 0 to 65,535. The language designers left unsigned types out to keep the type system small and avoid the signed/unsigned conversion bugs common in other languages; since Java 8, helper methods such as Integer.compareUnsigned() and Long.divideUnsigned() let you treat a signed int or long as unsigned when you really need to.

You rarely need to memorize the exact bounds, because each wrapper class exposes them as constants — Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, Byte.MAX_VALUE, and so on. Printing these is the reliable way to confirm a type's range at runtime rather than guessing:

// Read type limits from the wrapper constants
System.out.println("int min:  " + Integer.MIN_VALUE); // -2147483648
System.out.println("int max:  " + Integer.MAX_VALUE); //  2147483647
System.out.println("long max: " + Long.MAX_VALUE);    //  9223372036854775807
System.out.println("byte max: " + Byte.MAX_VALUE);    //  127

// char is the only unsigned primitive (0 to 65535)
char maxChar = Character.MAX_VALUE;

Common Mistakes and Troubleshooting

  • Integer overflow — adding two large int values can exceed 2,147,483,647 and wrap to a negative number. When values may be large, use long or BigInteger instead of int.
  • Float / double precision0.1 + 0.2 does not equal exactly 0.3 because of binary floating-point representation. For money and exact decimals, use BigDecimal rather than float or double.
  • char vs String confusion'A' (single quotes) is a char, while "A" (double quotes) is a String. Assigning "A" to a char is a compile error.
  • Uninitialized local variables — unlike class fields, local variables have no default value. Reading one before assigning a value is a compile-time error: "variable might not have been initialized."
  • Missing literal suffixlong big = 9000000000; fails to compile because the literal is treated as an int. Add the L suffix: 9000000000L. The same applies to f for float.

Conclusion

Java's 8 primitive data types — byte, short, int, long, float, double, char, and boolean — are the foundation of every program. They store values directly, have fixed sizes and ranges, and come with sensible defaults for class fields. Understand how they differ from reference types, how wrapper classes and autoboxing bridge the two worlds, and how widening and narrowing casting behave, and you will avoid the overflow, precision, and null-unboxing bugs that catch most developers. Data types are also a staple of technical screens, so review them alongside the wider Java interview questions. Master the basics here, then validate your Java automation across real browsers to ship with confidence.

Frequently Asked Questions

How many primitive data types are there in Java?

Java has exactly 8 primitive data types: byte, short, int, long, float, double, char, and boolean. Four are integer types, two are floating-point types, one is a character type, and one is boolean. Everything else in Java is a reference type.

Is String a primitive data type in Java?

No. String is a class (a reference type), not a primitive. It is one of the most common reference types in Java, but it stores an object reference rather than a raw value, so it is not counted among the 8 primitive data types.

What is the difference between int and Integer in Java?

int is a primitive that stores a 32-bit value directly and cannot be null. Integer is its wrapper class — an object that boxes an int so it can live in collections, hold null, and call methods. Autoboxing converts between them automatically.

What is the default value of a primitive in Java?

Numeric primitives default to 0 (0.0 for float and double), char defaults to the null character \u0000, and boolean defaults to false. These defaults apply only to instance and static fields — local variables have no default and must be initialized before use.

What is the difference between widening and narrowing casting?

Widening casting converts a smaller type to a larger one (int to long) automatically and safely. Narrowing casting converts a larger type to a smaller one (double to int) and must be written explicitly with a cast operator, because it can lose data or precision.

Are Java primitive data types signed or unsigned?

The integer types byte, short, int, and long are all signed two's complement, so they hold negative and positive values. The only unsigned primitive is char, which ranges from 0 to 65,535. Java has no unsigned keyword, though Integer and Long add unsigned helper methods from Java 8 onward.

Why doesn't Java have unsigned primitive types?

Java's designers kept the primitive set small and consistent to avoid the subtle conversion and comparison bugs that signed/unsigned mixing causes in languages like C. When you truly need unsigned math, use a larger signed type or the Integer.compareUnsigned() and Long.divideUnsigned() helpers introduced in Java 8.

Related Questions

Test Your Website on 3000+ Browsers

Get 100 minutes of automation test minutes FREE!!

Test Now...

KaneAI - Testing Assistant

World’s first AI-Native E2E testing agent.

...

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests