Core Java · Lesson 3
Variables and Data Types
Understanding Variables and Data Types
A variable is a named container that stores a value in memory, and every variable has a data type that determines what kind of data it can hold. Java enforces strict type checking, meaning you declare a variable's type once and can only store compatible values in it. This prevents bugs and makes code more predictable — the compiler catches type errors before your program runs, unlike dynamically-typed languages.
Primitive Data Types
Java has eight primitive data types, which are the basic building blocks for storing numbers, characters, and boolean values. Unlike objects, primitives are stored directly in memory and are extremely efficient. Here are the types organized by their purpose:
| Type | Size | Range | Purpose |
|---|---|---|---|
byte | 8 bits | -128 to 127 | Small integer values |
short | 16 bits | -32,768 to 32,767 | Larger small integers |
int | 32 bits | -2.1B to 2.1B | Standard integer type |
long | 64 bits | ~-9.2E18 to 9.2E18 | Very large integers |
float | 32 bits | ~±1.4E-45 to ±3.4E38 | Single-precision decimals |
double | 64 bits | ~±4.9E-324 to ±1.7E308 | Double-precision decimals (preferred) |
char | 16 bits | 0 to 65,535 | Single Unicode character |
boolean | 1 bit | true or false | Logical values |
public class PrimitiveTypes {
public static void main(String[] args) {
// Integer types
byte smallNumber = 100; // fits in 8 bits
short mediumNumber = 30000; // fits in 16 bits
int regularNumber = 1000000; // most common for integers
long bigNumber = 9000000000L; // note the 'L' suffix for long
// Floating-point types
float approximateValue = 3.14f; // 'f' suffix for float
double preciseValue = 3.14159265; // 'double' is the default
// Character and boolean
char letter = 'A'; // single character in quotes
boolean isJavaFun = true; // logical true/false
System.out.println("byte: " + smallNumber);
System.out.println("long: " + bigNumber);
System.out.println("double: " + preciseValue);
System.out.println("Is Java fun? " + isJavaFun);
}
}
Reference Data Types: Objects and Arrays
Beyond primitives, reference data types store references (memory addresses) to objects on the heap. The most common reference types are classes, interfaces, and arrays. When you create a variable of a reference type like String or ArrayList, the variable holds a pointer to the actual object in memory, not the data itself. This distinction matters: copying a reference doesn't copy the object.
public class ReferenceTypes {
public static void main(String[] args) {
// String is a reference type (object)
String message = "Hello, Java!";
String copy = message; // copy contains reference to same object
// Arrays are reference types
int[] scores = {85, 90, 78, 92};
String[] names = {"Alice", "Bob", "Charlie"};
// Custom objects
Person developer = new Person("Eve", 28);
developer.printInfo();
System.out.println("Message: " + message);
System.out.println("First score: " + scores[0]);
}
}
class Person {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
void printInfo() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
Variable Declaration, Initialization, and Scope
Declaration introduces a variable with a type, initialization assigns it a first value, and scope determines where that variable is accessible. Variables declared inside a method are local variables and only exist while that method is running. Variables declared inside a class are instance variables and persist as long as the object exists. Understanding scope prevents errors like "variable not found" and keeps code organized.
public class VariableScope {
private String globalMessage = "I'm an instance variable"; // scope: entire object
public static void main(String[] args) {
String localVar = "I'm local to main"; // scope: only inside main()
if (true) {
int blockVar = 42; // scope: only inside this if block
System.out.println(blockVar); // OK
}
// System.out.println(blockVar); // ERROR: blockVar doesn't exist here
demonstrateScope();
}
static void demonstrateScope() {
String methodVar = "Local to this method"; // scope: only in demonstrateScope()
System.out.println(methodVar);
}
}
Type Conversion: Implicit and Explicit Casting
Sometimes you need to convert a value from one type to another. Implicit casting (widening) happens automatically when converting a smaller type to a larger one with no data loss (e.g., int to double). Explicit casting (narrowing) requires you to manually cast when converting a larger type to smaller, potentially losing precision or data — the compiler forces you to acknowledge the risk.
public class TypeConversion {
public static void main(String[] args) {
// Implicit casting (widening) — safe, automatic
int wholeNumber = 100;
double decimalNumber = wholeNumber; // int → double automatically
System.out.println("Implicit: " + decimalNumber); // 100.0
// Explicit casting (narrowing) — must specify, may lose data
double pi = 3.14159;
int truncated = (int) pi; // double → int (note the cast)
System.out.println("Explicit: " + truncated); // 3 (decimal part lost)
// String conversion
int age = 25;
String ageText = String.valueOf(age); // int → String
int parsedAge = Integer.parseInt(ageText); // String → int
System.out.println("Converted: " + parsedAge);
}
}
Common Mistake: Assuming
==compares object contents. For reference types likeString, use.equals()instead.string1 == string2compares if they reference the same object, not if they have the same value. This catches many developers off guard when comparing Strings or other objects.
Best Practices for Variables and Types
- Choose the right type: use
intfor most integers,doublefor decimals,Stringfor text - Initialize variables before use: Java requires this; prevents mysterious
nullerrors - Use meaningful variable names:
totalScoreis clearer thantsorx - Declare variables close to use: reduces scope and makes code easier to follow
- Prefer
doubleoverfloat: doubles have more precision and are rarely slower - Be explicit with casts: even though Java may allow implicit casts, explicit ones show intent
Real-World Example: Processing Student Grades
A grade management system uses int for scores (0–100), double for GPAs (4.0 scale), String for student names, and boolean for enrollment status. When calculating class averages, the system implicitly casts scores to double for precision. When importing from a CSV file, it parses String values to int using Integer.parseInt(). This mix of types, combined with proper casting and conversion, allows the system to store, calculate, and report student progress accurately.
Quiz Check