Introduction
In this lesson, you will deepen your understanding of Java data types, how they are stored and used, and how to choose the right type for different situations. You will distinguish between primitive and reference (non-primitive) data types, work with variable declarations, understand default values, perform type casting and conversion, and learn to spot and fix common data type–related errors.
1. Overview of Java Data Types
Java data types fall into two broad categories:
- Primitive data types – store simple values directly (numbers, characters, booleans).
- Reference (non-primitive) data types – store references (addresses) to objects in memory.
2. Primitive Data Types
Java has eight primitive data types:
- byte – 8-bit signed integer
- short – 16-bit signed integer
- int – 32-bit signed integer (most common for whole numbers)
- long – 64-bit signed integer
- float – 32-bit floating-point
- double – 64-bit floating-point (most common for decimals)
- char – 16-bit Unicode character
- boolean –
trueorfalse
2.1 Declaring Primitive Variables (with Use Cases)
public class PrimitiveExamples {
public static void main(String[] args) {
int age = 25; // typical integer value
long population = 8_000_000_000L; // large whole number, needs 'L'
double price = 199.99; // decimal value
float temperature = 36.5F; // float needs 'F' suffix
char grade = 'A'; // single character
boolean isActive = true; // boolean flag
System.out.println("Age: " + age);
System.out.println("Population: " + population);
System.out.println("Price: " + price);
System.out.println("Temperature: " + temperature);
System.out.println("Grade: " + grade);
System.out.println("Is Active: " + isActive);
}
}
// Output
Age: 25
Population: 8000000000
Price: 199.99
Temperature: 36.5
Grade: A
Is Active: true
Explanation: Each variable uses a primitive type suitable for the value: int for typical counts, long for very large counts, double/float for decimals, char for a single character, and boolean for true/false.
3. Reference (Non-Primitive) Data Types
Reference types (also called non-primitive types) include:
- Classes (e.g.,
String,Scanner, custom classes) - Arrays (e.g.,
int[],String[]) - Interfaces
- Enums
They do not hold the data directly. Instead, they hold a reference (like a pointer) to an object stored in the heap.
3.1 Examples of Non-Primitive Types
public class ReferenceExamples {
public static void main(String[] args) {
String message = "Hello, Java"; // String object
int[] numbers = {1, 2, 3, 4}; // array object
String upper = message.toUpperCase(); // method call on String object
int length = numbers.length; // field access on array object
System.out.println(message);
System.out.println(upper);
System.out.println("First element: " + numbers[0]);
System.out.println("Array length: " + length);
}
}
// Output
Hello, Java
HELLO, JAVA
First element: 1
Array length: 4
Explanation: String and int[] are non-primitive. The variables message and numbers hold references to objects. Methods and fields (toUpperCase(), length) are available because they are objects, not raw primitive values.
3.2 Detailed View of Non-Primitive Data Types
- String: sequence of characters, immutable, widely used for text.
- Arrays: fixed-size collection of elements of the same type.
- User-defined classes: custom types that group fields and behavior.
- Collections (from Java libraries): e.g.,
ArrayList,HashMap(although not primitives, they are also reference types built on classes).
4. Default Values and Memory Behavior
4.1 Memory: Primitive vs Reference
Primitive variables
- Stored directly in the stack (or within objects on the heap).
- Contain the actual value (e.g.,
42,true).
Reference variables
- Store a reference (address) to an object in the heap.
- Multiple variables can reference the same object.
public class MemoryBehavior {
public static void main(String[] args) {
int x = 10; // primitive value 10
int y = x; // copy of value 10
x = 20; // changes only x
String s1 = "Hi"; // reference to String object
String s2 = s1; // same reference as s1
s1 = "Hello"; // s1 now refers to a new object
System.out.println("x: " + x + ", y: " + y);
System.out.println("s1: " + s1 + ", s2: " + s2);
}
}
// Output
x: 20, y: 10
s1: Hello, s2: Hi
Explanation: For primitives, y gets a copy of the value; changing x doesn’t affect y. For references, s1 and s2 originally point to the same object; reassigning s1 changes only what s1 points to.
4.2 Default Values
Default values apply to fields in classes, not local variables.
Primitives:
byte, short, int, long→0float, double→0.0char→\u0000(null character)boolean→false
Reference types:
null
public class Defaults {
int number; // default 0
boolean flag; // default false
String text; // default null (reference)
public static void main(String[] args) {
Defaults d = new Defaults();
System.out.println("number: " + d.number);
System.out.println("flag: " + d.flag);
System.out.println("text: " + d.text);
}
}
// Output
number: 0
flag: false
text: null
Explanation: Uninitialized fields get default values; local variables inside methods must be explicitly initialized or the code won’t compile.
5. Type Casting and Type Conversion
5.1 Widening Conversion (Safe, Automatic)
Widening goes from a smaller to a larger type (no data loss):
byte → short → int → long → float → double
public class WideningExample {
public static void main(String[] args) {
int small = 100;
long bigger = small; // automatic widening
double decimal = bigger; // automatic widening
System.out.println("small: " + small);
System.out.println("bigger: " + bigger);
System.out.println("decimal: " + decimal);
}
}
// Output
small: 100
bigger: 100
decimal: 100.0
5.2 Narrowing Conversion (Risky, Requires Cast)
Narrowing goes from larger to smaller type; may lose data.
public class NarrowingExample {
public static void main(String[] args) {
double value = 123.45;
int intValue = (int) value; // explicit cast
System.out.println("value: " + value);
System.out.println("intValue: " + intValue);
}
}
// Output
value: 123.45
intValue: 123
Explanation: The fractional part is lost when casting from double to int.
5.3 Converting Between Primitives and Reference Types
Common example: primitive ↔ String.
public class ConversionExample {
public static void main(String[] args) {
int number = 42;
String text = String.valueOf(number); // int -> String
String input = "123";
int parsed = Integer.parseInt(input); // String -> int
System.out.println("text: " + text);
System.out.println("parsed + 1: " + (parsed + 1));
}
}
// Output
text: 42
parsed + 1: 124
Explanation: String.valueOf converts any value to String. Wrapper classes like Integer provide parsing methods to convert from String back to primitives.
6. Common Data Type Errors and Fixes
6.1 Incompatible Assignment
public class TypeErrors {
public static void main(String[] args) {
// int x = 10.5; // ERROR: cannot assign double to int
double x = 10.5; // FIX: use double for decimal values
// String s = 100; // ERROR: cannot assign int to String
String s = "100"; // FIX: use quotes for text or String.valueOf(100)
System.out.println(x);
System.out.println(s);
}
}
// Output
10.5
100
6.2 Lossy Conversion Without Cast
public class LossyConversion {
public static void main(String[] args) {
double d = 9.99;
// int i = d; // ERROR: lossy conversion
int i = (int) d; // FIX: explicit cast, accept data loss
System.out.println(i);
}
}
// Output
9
6.3 Null Reference Errors
public class NullExample {
public static void main(String[] args) {
String name = null;
// System.out.println(name.length()); // RUNTIME ERROR: NullPointerException
if (name != null) { // FIX: always check for null
System.out.println(name.length());
} else {
System.out.println("name is null");
}
}
}
// Output
name is null
7. Primitive vs Non-Primitive: Key Differences
- Storage
- Primitive: holds actual value.
- Reference: holds address of an object.
- Default values
- Primitive: numeric
0, booleanfalse, char\u0000. - Reference:
null.
- Primitive: numeric
- Methods
- Primitive: no methods.
- Reference: can call methods and access fields.
- Mutability
- Primitive values are immutable; assignments create new values.
- Reference types can refer to mutable objects (e.g., arrays, lists).
Summary / Key Takeaways
In this lesson Java Data Types, you have learned:
- Java has two main categories of data types: primitive (8 built-in types) and reference (non-primitive) types such as classes, arrays, and interfaces.
- Primitive variables store actual values directly, while reference variables store addresses pointing to objects on the heap.
- Default values apply to fields: primitives get type-specific defaults like 0 or false, whereas reference types default to null.
- Choosing appropriate data types is context-dependent: use int/long for whole numbers, double/float for decimals, boolean for flags, and reference types for structured or text data.
- Widening conversions between numeric primitives happen automatically, but narrowing conversions require explicit casts and can lose data.
- Conversions between primitives and Strings are commonly done using String.valueOf and parsing methods from wrapper classes like Integer.parseInt.
- Typical data type errors include incompatible assignments, missing casts for narrowing conversions, and NullPointerException when dereferencing null references.
- Primitive and non-primitive types differ in memory behavior, method availability, and default values, which directly affect how you design and debug Java programs.