Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

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.
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:
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.
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.
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.
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:
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.
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 converts a value of one primitive type into another. Java distinguishes two directions:
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.
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;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.
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.
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.
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.
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.
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.
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.
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.
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