Ch 2.2 Variable Types
Java is a strongly typed language that requires you to specify the type of data to be stored in advance. The type of a variable determines how the value is stored and interpreted.
1. Primitive Types vs Reference Typesβ
Java's data types are divided into two main categories.
| Category | Primitive Type | Reference Type |
|---|---|---|
| Stored content | Stores the actual value directly | Stores the memory address of an object |
| Memory location | Stack | Heap |
| Varieties | 8 types (int, double, etc.) | Unlimited (String, arrays, classes, etc.) |
| Default value | Fixed per type (0, false, etc.) | null |
| Size | Fixed per type (1~8 bytes) | Varies by JVM (4 or 8 byte address) |
Primitive variable (Stack) Reference variable (Stack β Heap)
ββββββββββββββββ ββββββββββββββββ βββββββββββββββββββ
β int age=25 β β String name ββββββββΆβ "Alice" (Heap) β
β age: [25] β β name: [addr]β β (actual object) β
ββββββββββββββββ ββββββββββββββββ βββββββββββββββββββ
Primitive values are stored directly on the stack for fast access. Reference types store the address of a heap object on the stack.
2. All 8 Primitive Typesβ
There are exactly 8 primitive types, categorized as boolean, character, integer, and floating-point.
| Category | Type | Size | Range | Default | Wrapper Class |
|---|---|---|---|---|---|
| Boolean | boolean | 1 bit (JVM-dependent) | true / false | false | Boolean |
| Character | char | 2 bytes | '\u0000' ~ '\uFFFF' (0 ~ 65,535) | '\u0000' | Character |
| Integer | byte | 1 byte | -128 ~ 127 | 0 | Byte |
| Integer | short | 2 bytes | -32,768 ~ 32,767 | 0 | Short |
| Integer | int | 4 bytes | -2,147,483,648 ~ 2,147,483,647 | 0 | Integer |
| Integer | long | 8 bytes | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | 0L | Long |
| Floating-point | float | 4 bytes | Β±3.4 Γ 10^38 (7 decimal digits) | 0.0f | Float |
| Floating-point | double | 8 bytes | Β±1.8 Γ 10^308 (15 decimal digits) | 0.0d | Double |
public class AllPrimitiveTypes {
public static void main(String[] args) {
boolean isJavaFun = true; // boolean
char letter = 'J'; // character
byte tinyNum = 100; // integer (small range)
short smallNum = 30000; // integer (medium range)
int normalNum = 2000000; // integer (default, most commonly used)
long bigNum = 9_000_000_000L; // integer (large range, L suffix required)
float floatNum = 3.14f; // floating-point (f suffix required)
double doubleNum = 3.141592653; // floating-point (default, high precision)
System.out.println("boolean: " + isJavaFun);
System.out.println("char: " + letter);
System.out.println("byte: " + tinyNum);
System.out.println("short: " + smallNum);
System.out.println("int: " + normalNum);
System.out.println("long: " + bigNum);
System.out.println("float: " + floatNum);
System.out.println("double: " + doubleNum);
}
}
3. Literals and Notationβ
A literal is a fixed value written directly in code. Notation varies by type.
Integer Literalsβ
int decimal = 100; // Decimal (default)
int binary = 0b01100100; // Binary (0b prefix)
int octal = 0144; // Octal (0 prefix)
int hex = 0x64; // Hexadecimal (0x prefix)
long bigLong = 100L; // long literal (L or l suffix, uppercase recommended)
long billion = 1_000_000_000L; // Underscores for readability (Java 7+)
// All 4 above hold the same value (100)
System.out.println(decimal == binary); // true
System.out.println(binary == octal); // true
System.out.println(octal == hex); // true
Floating-Point Literalsβ
double d1 = 3.14; // double (default, no suffix)
double d2 = 3.14d; // double (explicit d suffix)
double d3 = 3.14e2; // Scientific notation = 314.0
float f1 = 3.14f; // float (f suffix required!)
float f2 = 3.14F; // float (F also works)
// 3.14 is a double by default, so float requires the f suffix
// float f3 = 3.14; // Error! possible lossy conversion from double to float
Character Literalsβ
char c1 = 'A'; // Character literal (single quotes)
char c2 = 65; // Specify character by integer value (A = 65)
char c3 = '\u0041'; // Direct Unicode notation (A)
char c4 = '\n'; // Special character (newline)
char c5 = '\t'; // Special character (tab)
// Escape sequences
// \' single quote
// \" double quote
// \\ backslash
// \n newline
// \t tab
// \r carriage return
boolean Literalsβ
boolean b1 = true;
boolean b2 = false;
boolean b3 = (10 > 5); // Conditional expressions can also be used as boolean values
4. Reference Types: String, Arrays, Classes, Interfacesβ
Reference types include everything except the 8 primitive types.
// String - most commonly used reference type
String greeting = "Hello, Java!";
String empty = ""; // Empty string
String nullStr = null; // References no object
// Arrays
int[] scores = {95, 88, 72, 100};
String[] names = {"Alice", "Bob", "Charlie"};
// Classes (user-defined)
// Student student = new Student("Alice", 20);
5. Special Treatment of Stringβ
String is a class but can be created with a literal (without new), just like a primitive. Java maintains a special memory space called the String Constant Pool for frequently used strings.
public class StringComparison {
public static void main(String[] args) {
// Literal method: uses String Pool (same content shares same object)
String s1 = "hello";
String s2 = "hello";
// new keyword: creates a new object every time (stored separately in heap)
String s3 = new String("hello");
String s4 = new String("hello");
// == : compares addresses (references)
System.out.println(s1 == s2); // true (same Pool object)
System.out.println(s1 == s3); // false (different objects)
System.out.println(s3 == s4); // false (different new objects)
// .equals() : compares content (values) <- always use this for strings!
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // true
System.out.println(s3.equals(s4)); // true
}
}
Always use .equals() when comparing Strings! Using == compares addresses and can produce unexpected results.
6. null and NullPointerExceptionβ
null is the state where a reference variable points to no object.
public class NullExample {
public static void main(String[] args) {
String name = null; // name points to nothing
System.out.println(name); // null (printing is fine)
// Calling a method on a null variable causes NullPointerException!
try {
int length = name.length(); // Error!
} catch (NullPointerException e) {
System.out.println("NullPointerException occurred!");
System.out.println("Cannot call methods on a null variable.");
}
// How to check for null
if (name != null) {
System.out.println("Length: " + name.length());
} else {
System.out.println("name is null.");
}
}
}
Since Java 14+, NullPointerException messages have been improved to clearly indicate which variable was null.
7. Wrapper Classesβ
Each primitive type has a corresponding wrapper class. These are used when a primitive needs to be treated as an object (collections, generics, etc.).
public class WrapperExample {
public static void main(String[] args) {
// Primitive -> Wrapper class (Boxing)
int primitiveInt = 42;
Integer wrappedInt = Integer.valueOf(primitiveInt); // Explicit Boxing
Integer autoBoxed = primitiveInt; // Auto-Boxing (Java 5+)
// Wrapper class -> Primitive (Unboxing)
int unboxed = wrappedInt.intValue(); // Explicit Unboxing
int autoUnboxed = wrappedInt; // Auto-Unboxing
// Useful wrapper class methods
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.toBinaryString(255)); // 11111111
System.out.println(Integer.parseInt("100")); // 100 (String -> int)
System.out.println(Double.parseDouble("3.14")); // 3.14 (String -> double)
}
}
8. Object Class β The Root of All Classesβ
Every Java class automatically inherits from Object. It sits at the top of Java's class hierarchy.
Object
βββ String
βββ Integer
βββ ArrayList
βββ Scanner
βββ (all user-defined classes)
public class ObjectExample {
public static void main(String[] args) {
// Object type can hold any reference variable
Object obj1 = "Hello"; // String as Object
Object obj2 = 42; // Integer as Object (autoboxing)
Object obj3 = new int[]{1, 2, 3}; // Array as Object
// toString() - available on all objects (inherited from Object)
System.out.println(obj1.toString()); // Hello
System.out.println(obj2.toString()); // 42
}
}
9. Constants and Numeric Literal Readabilityβ
public class LiteralReadability {
// Constants are typically declared as static final at class level
static final double PI = 3.14159265358979;
static final int SECONDS_PER_DAY = 24 * 60 * 60; // 86400
public static void main(String[] args) {
// Java 7+ numeric underscore notation for readability
long population = 8_000_000_000L; // 8 billion
int creditCardNum = 1234_5678_9012_3456; // card number
double avogadro = 6.022_140_76e23; // Avogadro's number
System.out.println("World population: " + population);
System.out.println("Seconds per day: " + SECONDS_PER_DAY);
System.out.println("Pi: " + PI);
}
}
10. Practical Example: Declaring and Printing Various Type Variablesβ
public class TypesDemo {
public static void main(String[] args) {
// Personal information
String name = "Java Lee";
int age = 28;
char gender = 'M';
boolean isMarried = false;
// Physical information
double height = 175.5;
float weight = 68.3f;
// Financial information
long salary = 3_500_000L; // Monthly salary
double taxRate = 0.033; // Tax rate 3.3%
// Calculations
long tax = (long)(salary * taxRate);
long netSalary = salary - tax;
// Output
System.out.println("===== Employee Info =====");
System.out.printf("Name: %s%n", name);
System.out.printf("Age: %d%n", age);
System.out.printf("Gender: %c%n", gender);
System.out.printf("Married: %b%n", isMarried);
System.out.printf("Height: %.1f cm%n", height);
System.out.printf("Weight: %.1f kg%n", weight);
System.out.printf("Salary: %,d%n", salary);
System.out.printf("Tax (%.1f%%): %,d%n", taxRate * 100, tax);
System.out.printf("Net Salary: %,d%n", netSalary);
}
}
Output:
===== Employee Info =====
Name: Java Lee
Age: 28
Gender: M
Married: false
Height: 175.5 cm
Weight: 68.3 kg
Salary: 3,500,000
Tax (3.3%): 115,500
Net Salary: 3,384,500
Summaryβ
- Java data types: 8 primitive types+ reference types (unlimited)
- Primitives: value stored directly on stack, 8 types (boolean, char, byte, short, int, long, float, double)
- Reference types: address of heap object stored on stack (String, arrays, classes, etc.)
- Always use
.equals()for String comparison(==compares addresses) null: initial state of reference variables, causes NPE when methods are called- Wrapper classes: object versions of primitives (Integer, Double, etc.)
- All classes inherit from
Object