Data Types in Java
Explore Java's primitive types (int, long, double, boolean, char, byte, short, float), their wrapper classes, and the difference between stack and heap allocation.
Primitive Types
Java has 8 primitive types. They are not objects — they store raw values directly in memory (on the stack), which makes them fast and memory-efficient. Every primitive has a fixed size regardless of the platform.
1. Integer Types (byte, short, int, long)
Used for whole numbers. Choose the type based on the range of values you need.
2. Floating-Point Types (float, double)
Used for decimal numbers. `double` is the default; `float` saves memory at the cost of precision.
3. boolean and char
`boolean` stores true/false. `char` stores a single Unicode character.
Wrapper Classes
Every primitive type has a corresponding wrapper class in `java.lang`. Wrappers turn primitives into objects so they can be used in collections (like `ArrayList`), accept `null`, and provide useful utility methods. Java automatically converts between primitives and wrappers through **autoboxing** and **unboxing**.
1. Primitive → Wrapper Mapping
Each primitive has an exact wrapper counterpart. Wrapper class names are capitalized.
2. Autoboxing & Unboxing
Java automatically converts between primitives and their wrapper objects when needed.
3. Wrapper Utility Methods
Wrapper classes provide static methods for parsing, converting, and inspecting values.
Stack vs Heap Memory
Java manages memory in two regions: the **stack** and the **heap**. Primitives live on the stack (fast, short-lived). Objects (including wrapper instances) live on the heap (garbage-collected, longer-lived). Understanding this distinction helps explain why `==` behaves differently for primitives vs objects.
1. Primitives Live on the Stack
Primitive variables store their value directly. Copying a primitive copies the actual value.
2. Objects Live on the Heap
Object variables store a reference (memory address). Copying a reference means both variables point to the same object.
Type Casting
Type casting converts a value from one type to another. Java supports two kinds: - **Widening** (implicit): smaller type → larger type, done automatically. - **Narrowing** (explicit): larger type → smaller type, requires a cast and may lose data.
1. Widening Casting (Implicit)
Java automatically promotes a smaller type to a larger compatible type — no data is lost.
2. Narrowing Casting (Explicit)
Converting a larger type to a smaller type requires an explicit cast `(type)`. Data may be truncated or lost.
Dynamic Typing (using Object)
Java is a statically typed language — every variable has a fixed type at compile time. However, `Object` is the root of all Java classes, so an `Object` variable can hold any value. This gives a form of dynamic-like flexibility, at the cost of losing compile-time type safety. Java 10+ `var` is a related but different concept: it infers a static type at compile time.
1. Object — Hold Any Value
`Object` is the superclass of every class in Java. An `Object` variable can store any type — primitive (autoboxed) or reference.
2. Casting Object Back to Its Real Type
To use the real methods of the stored type, you must cast the `Object` back down. Use `instanceof` to check safely before casting.
3. Object vs var — Key Difference
`Object` is truly dynamic (type known only at runtime). `var` is statically inferred (type locked at compile time). They look similar but behave very differently.