Skip to lesson
CodeLangs AISoftware Training Institute
Variables, Data Types and Memory Basics

Chapter 3 · Java Type System

Variables, Data Types and Memory Basics

Learn Java variables, primitive data types, reference values, scope, lifetime, numeric literals, overflow, and the conceptual stack and heap memory model through examples and interactive visual tools.

  • 8,196words
  • 38min read
  • 20quiz items
  • 21practice tools

Before we start writing larger Java programs, there is one very basic question we need to answer:

Where does a program keep its data?

Imagine that we are building an employee-management application.

We may need to remember:

  • employee ID
  • employee name
  • employee salary
  • whether the employee is active
  • employee grade
  • total employee count

A program cannot work with such information unless it has some way to store values while it is running.

Java gives us variables for this purpose.

But variables are only the beginning.

Once we create a variable, several more questions naturally appear:

  • What type of value can it hold?
  • How much memory does that value require?
  • What happens if we do not assign a value?
  • Where does Java keep the variable?
  • How long does the variable exist?
  • Who can access it?
  • What is the difference between primitive values and objects?
  • What is stored in stack memory?
  • What is stored in heap memory?
  • What happens when a variable refers to an object?

That is what this chapter is really about.

By the end of this chapter, variables should no longer feel like simple syntax such as:

Java
int age = 25;

You should understand what that line means from the perspective of:

Java syntax → type system → memory → scope → lifetime → coding → debugging → production → interview.


1. First Understand the Idea of a Value#

Before understanding variables, think about a simple value:

Output
25

25 is simply a number.

Similarly:

Output
45000.50
'A'
true
"Rahul"

are all values.

But suppose your program needs to use 25 repeatedly.

Writing 25 everywhere would be difficult because the program would not know what 25 represents.

Is it:

  • age?
  • quantity?
  • employee ID?
  • marks?
  • number of attempts?

We need a meaningful name connected to the value.

That gives us our first important concept.

2. What Is a Variable?#

A variable is a named storage location used by a program to hold a value.

For a beginner, you can mentally imagine:

Output
Variable Name
     ↓
   age
 ┌───────┐
 │  25   │
 └───────┘

Here:

  • age is the name
  • 25 is the value

In Java we can write:

Java
int age = 25;

Read it naturally:

Create a variable named age that can hold an int value and initially store 25 in it.

There are three important pieces:

Output
int   age   =   25;
│      │        │
│      │        └── value
│      └─────────── variable name
└────────────────── data type

Why does Java need a data type?#

Consider:

Output
25

and:

Output
25.75

and:

Output
'A'

and:

Output
true

They represent completely different kinds of information.

Java is a statically typed language.

That means Java normally knows the type of a variable at compile time.

For example:

Java
int age = 25;

Java knows that age is intended to hold an integer.

Therefore this is invalid:

Java
int age = "Twenty Five";

The variable was declared as int, but the supplied value is a String.

That produces a compile-time error.


3. Variable Declaration#

Now suppose we know that we will need an employee's age, but we do not yet know the actual value.

Java allows us to create the variable first.

Java
int age;

This is called variable declaration.

The declaration tells Java:

  1. the variable's type
  2. the variable's name

Here:

Output
int age;
│   │
│   └── variable name
└────── data type

No explicit value was assigned in this statement.

General form#

Java
dataType variableName;

Examples:

Java
int age;
double salary;
char grade;
boolean active;

Notice that declaration and value assignment do not have to happen in the same statement.

That leads naturally to the next idea.


4. Variable Initialization#

Suppose we declared:

Java
int age;

Later we receive the employee's age.

Java
age = 25;

The first value assigned to a variable is commonly called its initialization.

We can also declare and initialize together:

Java
int age = 25;

Declaration only#

Java
int age;

Declaration + initialization#

Java
int age = 25;

You will frequently see the second form because it prevents a variable from temporarily existing without a meaningful value.


5. Assignment#

The = symbol in Java is the assignment operator.

This is extremely important:

Java
age = 25;

does not mathematically mean:

Output
age equals 25

Instead it means:

Evaluate the value on the right side and store that value in the variable on the left side.

Think of the direction:

Output
age = 25
      │
      └────────► stored into age

Another example:

Java
int first = 10;
int second = first;

Execution:

Output
first = 10

second = first

Java reads first
       ↓
gets 10
       ↓
stores 10 into second

Now:

Output
first  = 10
second = 10

For primitive types, second receives its own primitive value.


6. Variable Reassignment#

Now suppose an employee's salary changes.

Java
double salary = 50000.0;

Later:

Java
salary = 55000.0;

This is reassignment.

The variable already contained a value and receives another value.

Conceptually:

Output
Before

salary
┌───────────┐
│ 50000.0   │
└───────────┘

salary = 55000.0;

After

salary
┌───────────┐
│ 55000.0   │
└───────────┘

The old primitive value is replaced as far as that variable is concerned.

Example:

Java
public class ReassignmentDemo {
    public static void main(String[] args) {
        int score = 50;
        System.out.println(score);

        score = 75;
        System.out.println(score);
    }
}

Output:

Output
50
75

7. One Important Restriction: Type Compatibility#

Once a variable is declared with a type, you cannot arbitrarily change its type.

Java
int age = 25;

Later this is valid:

Java
age = 30;

But this is not:

Java
age = true;

Nor:

Java
age = "Thirty";

Why?

Because age is an int variable.

The declared type controls which values may legally be assigned to it.


8. Primitive Data Types#

So far we have used types such as int, double, char, and boolean.

These belong to a special Java category called primitive types.

Java has exactly eight primitive data types:

Output
byte
short
int
long
float
double
char
boolean

Primitive types represent basic values directly rather than ordinary Java objects.

They fall naturally into four groups:

Output
Primitive Types
│
├── Integer
│   ├── byte
│   ├── short
│   ├── int
│   └── long
│
├── Floating Point
│   ├── float
│   └── double
│
├── Character
│   └── char
│
└── Logical
    └── boolean

Let us understand each one.


9. byte#

Suppose we need to store a very small whole number.

Using a huge numeric type would sometimes be unnecessary.

Java provides:

Java
byte

A byte is an 8-bit signed integral primitive type.

Range:

Output
-128 to 127

Example:

Java
byte level = 100;

Valid:

Java
byte temperature = -20;

Invalid:

Java
byte value = 128;

128 is outside the byte range.

Size#

Output
8 bits = 1 byte

Typical usage#

byte is particularly useful when handling raw binary data, byte buffers, streams, files, or network data.

It is less common for ordinary business counters than int.


10. short#

What if byte is too small but we still need only a modest integer range?

Java provides:

Java
short

Size:

Output
16 bits = 2 bytes

Range:

Output
-32,768 to 32,767

Example:

Java
short yearCode = 2026;

Although short exists, normal application code frequently uses int instead unless there is a specific reason to choose short.


11. int#

For normal whole numbers, Java developers most commonly use:

Java
int

Size:

Output
32 bits = 4 bytes

Range:

Output
-2,147,483,648
to
2,147,483,647

Example:

Java
int age = 36;
int employeeCount = 5000;
int marks = 85;

For integer literals such as:

Java
10
500
100000

Java normally treats them as int when they fit within the int range.

That makes int the natural default choice for most whole-number calculations.


12. long#

Now think about data such as:

  • very large counters
  • timestamps
  • large database IDs
  • number of milliseconds

An int may be too small.

Java provides:

Java
long

Size:

Output
64 bits = 8 bytes

Range:

Output
-9,223,372,036,854,775,808
to
9,223,372,036,854,775,807

Example:

Java
long population = 8_000_000_000L;

Notice the L.

This deserves attention.

Java normally interprets an integer literal as int.

If the literal itself exceeds the int range, we need to tell Java that it is a long literal.

Java
long population = 8_000_000_000L;

Prefer uppercase L.

Although lowercase l is legal:

Java
long number = 100l;

it looks dangerously similar to digit 1.

Preferred:

Java
long number = 100L;

13. float#

Whole numbers are not enough for many applications.

We may need:

Output
10.5
98.6
3.14

Java has two primitive floating-point types.

The smaller is:

Java
float

Size:

Output
32 bits = 4 bytes

Example:

Java
float temperature = 36.5F;

Why the F?

Because a decimal floating-point literal is double by default.

Therefore this fails:

Java
float temperature = 36.5;

Java sees 36.5 as a double.

We need:

Java
float temperature = 36.5F;

or:

Java
float temperature = 36.5f;

Uppercase or lowercase F is valid.


14. double#

For most general decimal calculations, Java developers normally choose:

Java
double

Size:

Output
64 bits = 8 bytes

Example:

Java
double salary = 75000.50;

No suffix is required because decimal literals are double by default.

Java
double pi = 3.14159;

15. A Critical Floating-Point Warning#

At this point you may naturally think:

If double stores decimal values, can I use it for money?

You technically can store values that look like monetary amounts:

Java
double price = 10.99;

But binary floating-point types cannot represent every decimal fraction exactly.

For example:

Java
public class FloatingPointDemo {
    public static void main(String[] args) {
        double result = 0.1 + 0.2;
        System.out.println(result);
    }
}

You may see:

Output
0.30000000000000004

This is not Java randomly making a mistake.

It is a consequence of binary floating-point representation.

Production rule#

For calculations requiring exact decimal arithmetic—especially financial calculations—developers commonly use BigDecimal.

BigDecimal is not a primitive type, so we will not turn this section into a complete BigDecimal lesson.

For now remember:

Output
Scientific/general approximate decimal calculations
→ float/double may be appropriate

Exact decimal financial calculation
→ investigate BigDecimal

16. char#

Now suppose we need to store a single character.

Java provides:

Java
char

Example:

Java
char grade = 'A';

Notice single quotes:

Java
'A'

A char stores a UTF-16 code unit.

Its size is:

Output
16 bits = 2 bytes

Its numeric range is:

Output
0 to 65,535

A char is unsigned.

Examples:

Java
char letter = 'J';
char digit = '7';
char symbol = '@';

A common beginner mistake is:

Java
char grade = "A";

This is invalid because "A" is a String, not a char.

Correct:

Java
char grade = 'A';

17. char Is Also Numeric#

This surprises many beginners.

Consider:

Java
char ch = 'A';
System.out.println((int) ch);

Output:

Output
65

The character 'A' corresponds to numeric value 65.

Because char represents a UTF-16 code unit, numeric operations are possible.

Example:

Java
char ch = 'A';
ch++;
System.out.println(ch);

Output:

Output
B

This does not mean you should treat all text as numbers.

It simply reflects Java's character representation.


18. boolean#

Programs constantly make decisions.

For example:

Output
Is employee active?
Is payment completed?
Is user authenticated?
Did validation succeed?

These are true/false conditions.

Java provides:

Java
boolean

A boolean variable holds:

Output
true
false

Example:

Java
boolean active = true;
boolean deleted = false;

Unlike some languages, Java does not treat integer 0 and 1 as booleans.

Invalid:

Java
boolean active = 1;

Correct:

Java
boolean active = true;

Java's language specification defines boolean values and behavior, but does not specify a simple fixed storage size in the same way that it does for numeric primitive value ranges.

Therefore avoid interview answers such as:

"boolean is always exactly one byte."

That is not a portable Java-language guarantee.


19. Primitive Type Size Summary#

TypeConceptual Java WidthTypical Purpose
byte8 bitsSmall integers, raw bytes
short16 bitsSmall integer range
int32 bitsGeneral integers
long64 bitsLarge integers
float32 bitsSingle-precision floating point
double64 bitsDouble-precision floating point
char16 bitsUTF-16 code unit
booleanJVM/language representation not expressed as a fixed numeric width for normal Java semanticstrue / false

20. Primitive Numeric Ranges#

TypeMinimumMaximum
byte-128127
short-32,76832,767
int-2,147,483,6482,147,483,647
long-9,223,372,036,854,775,8089,223,372,036,854,775,807
char065,535

Floating-point types use IEEE 754 representation, so describing their useful behavior requires more than simply listing an integer-style range.

The important beginner distinction is:

Output
float  → 32-bit floating point
double → 64-bit floating point

and:

Output
double provides greater precision than float

21. Default Values#

Now an important question appears.

What happens if we declare a variable but do not explicitly initialize it?

The answer depends on where the variable is declared.

This distinction is extremely important.

Suppose a variable is a field of an object.

Java
public class Employee {
    int age;
    boolean active;
}

Java supplies default values for fields.

Typical defaults:

TypeDefault
byte0
short0
int0
long0L
float0.0F
double0.0D
char'\u0000'
booleanfalse
Reference typenull

Example:

Java
public class DefaultValueDemo {
    int count;
    double salary;
    boolean active;
    String name;

    public static void main(String[] args) {
        DefaultValueDemo demo = new DefaultValueDemo();

        System.out.println(demo.count);
        System.out.println(demo.salary);
        System.out.println(demo.active);
        System.out.println(demo.name);
    }
}

Output:

Output
0
0.0
false
null

22. Local Variables Do NOT Automatically Receive Default Values#

Now suppose the variable is inside a method.

Java
public static void main(String[] args) {
    int age;
    System.out.println(age);
}

This does not compile.

Why?

Because age is a local variable and Java requires local variables to be definitely assigned before they are read.

Correct:

Java
public static void main(String[] args) {
    int age = 25;
    System.out.println(age);
}

This distinction is one of the most common Java interview questions.

Remember:

Output
Fields
→ receive default values

Local variables
→ must be assigned before use

23. We Now Need to Distinguish Variables by Where They Live#

Until now, we have mostly talked about variables as if they were all the same.

But consider these:

Java
class Employee {
    int age;

    static int count;

    void print() {
        int value = 10;
    }
}

There are three different categories here:

Output
age   → instance variable
count → static variable
value → local variable

Each has different ownership, lifetime, accessibility, and memory behavior.

Let us understand them one at a time.


24. Local Variables#

A variable declared inside a method, constructor, or applicable block is normally a local variable.

Example:

Java
public class LocalVariableDemo {
    public static void main(String[] args) {
        int age = 25;
        System.out.println(age);
    }
}

age belongs to the execution of main().

Another example:

Java
public static void calculate() {
    int total = 100;
}

total is local to calculate().

Important properties#

Local variables:

  • do not receive automatic default values
  • must be definitely assigned before reading
  • exist only within their scope
  • are not accessed through an object field syntax
  • disappear from practical use when their execution scope ends

25. Instance Variables#

Suppose every employee object should have its own salary.

Java
class Employee {
    double salary;
}

salary is declared inside the class but outside methods, constructors, and initializer blocks.

Because it is not declared static, it is an instance variable, also commonly called an instance field.

Each object gets its own logical field value.

Java
public class Employee {
    int age;

    public static void main(String[] args) {
        Employee first = new Employee();
        Employee second = new Employee();

        first.age = 25;
        second.age = 40;

        System.out.println(first.age);
        System.out.println(second.age);
    }
}

Output:

Output
25
40

Mental model:

Output
first object
┌──────────┐
│ age = 25 │
└──────────┘

second object
┌──────────┐
│ age = 40 │
└──────────┘

Each instance has its own age.


26. Static Variables#

Now imagine employee count.

Do we want every employee object to maintain a completely independent total count?

Usually no.

We want one value associated with the class.

That is where static is useful.

Java
class Employee {
    static int count;
}

A static field belongs to the class rather than to each individual object.

Example:

Java
public class Employee {
    static int count = 0;

    Employee() {
        count++;
    }

    public static void main(String[] args) {
        new Employee();
        new Employee();
        new Employee();

        System.out.println(Employee.count);
    }
}

Output:

Output
3

Conceptually:

Output
Employee class
     │
     └── count = 3

Objects:
Employee #1
Employee #2
Employee #3

All instances refer conceptually to the same class-level static field.

Preferred access#

Although Java may permit accessing a static field through an object expression in some circumstances, prefer:

Java
Employee.count

rather than:

Java
employee.count

because it makes class ownership clear.


27. Local vs Instance vs Static Variables#

DimensionLocalInstanceStatic
DeclaredInside method/block/constructorClass body, non-staticClass body with static
Belongs toCurrent execution scopeObject instanceClass
Default valueNo usable automatic default before readYesYes
One copy per object?NoYesNo
Typical accessDirect within scopeThrough object / current instanceUsually ClassName.field
LifetimeRelated to execution scopeGenerally tied to object's reachability/lifetimeGenerally tied to class loading/lifecycle

28. Constants#

Sometimes a value should not change after it has been initialized.

Examples:

  • mathematical constant
  • maximum retry count
  • configuration key name
  • fixed business code

Java uses final to prevent reassignment.

Example:

Java
final int maxAttempts = 3;

After assignment:

Java
maxAttempts = 5;

causes a compile-time error.


29. final Variables#

A final variable can be assigned only once.

Example:

Java
final int age = 25;

This is invalid:

Java
age = 30;

But there is an important nuance.

final means:

The variable cannot be reassigned after its single assignment.

For primitive variables:

Java
final int value = 10;

the primitive value cannot change through reassignment.

For reference variables:

Java
final StringBuilder builder = new StringBuilder("Java");

the variable builder cannot be made to refer to another object:

Java
builder = new StringBuilder("Python");

Invalid.

But the object itself may still be mutable:

Java
builder.append(" Programming");

Valid.

This distinction is critical.

Output
final reference
≠ automatically immutable object

30. Constant Naming Convention#

Class constants are commonly written using:

Java
static final

Example:

Java
public class RetryConfig {
    public static final int MAX_RETRY_COUNT = 3;
}

Naming convention:

Output
UPPER_SNAKE_CASE

Examples:

Java
MAX_RETRY_COUNT
DEFAULT_PORT
SECONDS_PER_MINUTE

This is a convention, not a special compiler rule.


31. Reference Variables#

So far primitive variables have been relatively simple.

Java
int age = 25;

But what happens here?

Java
Employee employee = new Employee();

employee is not an Employee object itself.

It is a reference variable whose value refers to an object.

A beginner-friendly mental model:

Output
Reference variable
employee
    │
    │ reference
    ▼
┌──────────────┐
│ Employee     │
│ object       │
└──────────────┘

The actual JVM representation is implementation-sensitive, so avoid oversimplifying references as guaranteed physical memory addresses.

The correct conceptual rule is:

A reference variable holds a reference value that can identify an object or be null.

32. null#

A reference variable may hold:

Java
null

Example:

Java
Employee employee = null;

That means it currently refers to no object.

If we then attempt:

Java
employee.getName();

we may get a NullPointerException.

This is one of the most important practical consequences of reference variables.


33. Primitive vs Reference Types#

Now the difference becomes clearer.

Primitive#

Java
int age = 25;

age directly represents the primitive value 25.

Reference#

Java
Employee employee = new Employee();

employee stores a reference value referring to an object.

Comparison:

DimensionPrimitiveReference
Examplesint, double, char, booleanString, arrays, custom classes
HoldsPrimitive valueReference value
Can be nullNoYes
Object requiredNoUsually refers to object/array
Built-in primitive typesExactly 8Huge number of reference types
Methods directly defined on primitive valueNo object methodsReferenced objects can provide methods

34. Primitive Assignment vs Reference Assignment#

This is extremely important.

Primitive assignment#

Java
int first = 10;
int second = first;

second = 20;

System.out.println(first);
System.out.println(second);

Output:

Output
10
20

Why?

second received a copy of the primitive value.

Conceptually:

Output
first  = 10
second = 10

Then:

Output
second = 20

does not affect first.


35. Reference Assignment#

Now consider:

Java
StringBuilder first = new StringBuilder("Java");
StringBuilder second = first;

second.append(" SE");

System.out.println(first);
System.out.println(second);

Output:

Output
Java SE
Java SE

Why?

Both variables refer to the same mutable object.

Conceptually:

Output
first ──────┐
            ▼
        ┌─────────┐
        │ Java SE │
        └─────────┘
            ▲
second ─────┘

The reference value was copied, not the object itself.

That distinction causes many real-world bugs.


36. Stack and Heap: First Build the Correct Mental Model#

You may have heard:

Primitive variables are stored on stack and objects are stored on heap.

That sentence is too simplistic to be used as a universal Java rule.

A more useful introductory model is:

  • method execution is associated with stack frames
  • local execution state is associated with those frames
  • ordinary dynamically created objects are typically allocated on the heap
  • references can appear in local variables or as object fields
  • JVM optimizations may change physical implementation details

For interviews at a beginner level, use a conceptual model without making absolute implementation claims that the Java language itself does not guarantee.


37. Stack Memory Basics#

Whenever a method is called, the JVM manages execution information associated with that method invocation.

You can mentally represent this using a stack frame.

Example:

Java
public static void main(String[] args) {
    int age = 25;
    calculate();
}

static void calculate() {
    int value = 10;
}

Conceptual flow:

Output
main() called

Call Stack
┌───────────────┐
│ main frame    │
│ age = 25      │
└───────────────┘

Then calculate() is called:

Output
Call Stack
┌───────────────┐
│ calculate     │
│ value = 10    │
├───────────────┤
│ main          │
│ age = 25      │
└───────────────┘

When calculate() returns:

Output
Call Stack
┌───────────────┐
│ main          │
│ age = 25      │
└───────────────┘

The frame associated with calculate() is no longer needed.

This explains local-variable lifetime conceptually.


38. Heap Memory Basics#

Objects created using expressions such as:

Java
new Employee()

are normally associated with heap allocation in the standard JVM mental model.

Example:

Java
Employee employee = new Employee();

Conceptually:

Output
Method execution
      │
      │ employee reference
      ▼
Heap
┌────────────────┐
│ Employee object│
└────────────────┘

If no reachable references remain to an object, it may eventually become eligible for garbage collection.

Important:

Eligible for garbage collection does not mean "immediately deleted at this exact line."

Garbage collection timing is controlled by the JVM.


39. Stack vs Heap — Practical Comparison#

DimensionStack / Call Stack ModelHeap Model
Main purposeMethod execution framesObjects and arrays
LifetimeOften tied to method invocationDepends on object reachability
ManagementFrames pushed/popped with callsManaged with garbage collection
Common failureStackOverflowErrorOutOfMemoryError scenarios
Access patternExecution-orientedObject-oriented shared data

Again, this is a developer mental model, not a promise about every low-level JVM optimization.


40. Variable Scope#

Now imagine this code:

Java
public static void main(String[] args) {
    int age = 25;

    if (age >= 18) {
        String message = "Adult";
    }

    System.out.println(message);
}

Will this compile?

No.

Why?

message was declared inside the if block.

Its scope is limited to that block.

Scope means:

The region of source code in which a name can legally be accessed.

Correct:

Java
public static void main(String[] args) {
    int age = 25;

    if (age >= 18) {
        String message = "Adult";
        System.out.println(message);
    }
}

41. Block Scope#

A pair of braces introduces a block in many Java constructs.

Java
{
    int value = 10;
}

Outside that block:

Java
System.out.println(value);

value is not accessible.

Example:

Java
public class ScopeDemo {
    public static void main(String[] args) {
        int outer = 10;

        {
            int inner = 20;
            System.out.println(outer);
            System.out.println(inner);
        }

        System.out.println(outer);
    }
}

inner cannot be used after its block ends.


42. Variable Lifetime#

Scope and lifetime are related but not identical concepts.

Scope#

Where the variable's name is accessible in source code.

Lifetime#

The period during program execution for which its associated storage/value context exists.

Example:

Java
void process() {
    int count = 10;
}

count is local to a particular invocation of process().

When that method call finishes, that invocation's local execution state ends.

Instance fields generally live as part of the object state for as long as that object remains alive/reachable.

Static fields generally participate in class-level lifecycle.


43. Scope vs Lifetime#

QuestionScopeLifetime
ConcernSource-code visibilityRuntime existence
Main question"Can I access this name here?""How long does this state exist?"
ExampleLocal block boundariesMethod call/object/class lifecycle

This distinction is frequently asked in interviews.


44. Literals#

Until now we have written values directly:

Java
10
3.14
'A'
true

Values written directly in source code are called literals.

Examples:

Java
int count = 10;
double price = 99.50;
char grade = 'A';
boolean active = true;

Here:

Output
10    → integer literal
99.50 → floating-point literal
'A'   → character literal
true  → boolean literal

Java supports several useful literal forms.


45. Integer Literals#

Basic decimal integer:

Java
int value = 100;

Negative value:

Java
int value = -100;

Technically the minus sign is an operator applied to a literal, but from normal developer usage we naturally speak about negative numeric values.


46. Floating-Point Literals#

Examples:

Java
double price = 10.5;
double scientific = 1.2e3;
float temperature = 36.5F;

1.2e3 means:

Output
1.2 × 10³
= 1200.0

Example:

Java
System.out.println(1.2e3);

Output:

Output
1200.0

47. Character Literals#

Character literals use single quotes:

Java
char grade = 'A';

Escape characters are also possible.

Examples:

Java
char newline = '\n';
char tab = '\t';
char quote = '\'';
char backslash = '\\';

Unicode escape form:

Java
char letter = '\u0041';

\u0041 represents A.


48. Boolean Literals#

Java provides exactly two boolean literal values:

Java
true
false

Example:

Java
boolean loggedIn = true;
boolean deleted = false;

They are keywords and are written lowercase.

Invalid:

Java
boolean value = True;

Correct:

Java
boolean value = true;

49. Binary Literals#

Sometimes developers need to work directly with bit patterns.

Binary uses digits:

Output
0 and 1

Java allows binary literals with prefix:

Output
0b

or:

Output
0B

Example:

Java
int value = 0b1010;
System.out.println(value);

Output:

Output
10

Because:

Output
1010₂ = 10₁₀

50. Octal Literals#

Octal uses base 8.

Java indicates an octal integer literal with a leading 0.

Example:

Java
int value = 012;
System.out.println(value);

Output:

Output
10

Why?

Output
12₈ = 10₁₀

Common production warning#

Leading zeroes can confuse readers.

Example:

Java
int code = 010;

This is decimal 8, not decimal 10.

Unless octal is genuinely intended, avoid accidental leading zeroes.


51. Hexadecimal Literals#

Hexadecimal uses base 16.

Digits:

Output
0-9
A-F

Prefix:

Output
0x

or:

Output
0X

Example:

Java
int value = 0xFF;
System.out.println(value);

Output:

Output
255

Hexadecimal is commonly encountered in:

  • bit masks
  • low-level systems work
  • colors
  • protocols
  • debugging
  • binary representations

52. Comparing Number Literal Systems#

The same decimal value 10 can be represented as:

Java
int decimal = 10;
int binary = 0b1010;
int octal = 012;
int hexadecimal = 0xA;

All represent numeric value 10.

Java
System.out.println(decimal);
System.out.println(binary);
System.out.println(octal);
System.out.println(hexadecimal);

Output:

Output
10
10
10
10

53. Underscores in Numeric Literals#

Large numbers can become difficult to read.

Compare:

Java
int salary = 1000000;

with:

Java
int salary = 1_000_000;

The underscore improves readability.

Java ignores permitted numeric-literal underscores when evaluating the numeric value.

Java
long accountNumberPart = 123_456_789L;

The value is still:

Output
123456789

Valid examples#

Java
int million = 1_000_000;
int binary = 0b1010_1010;
long large = 9_000_000_000L;
double amount = 1_234.56;

Invalid placements#

You cannot place underscores arbitrarily.

For example, patterns such as these are invalid:

Java
int a = _100;
int b = 100_;
double c = 10_.5;
double d = 10._5;

The underscore must occur within the appropriate digit sequence, not at arbitrary boundaries.


54. Type Inference Does Not Change the Underlying Type Rules#

In newer Java versions you may encounter local variable type inference:

Java
var age = 25;

But var does not make Java dynamically typed.

The compiler still determines a concrete type.

For this chapter, the explicit form is better for learning:

Java
int age = 25;

rather than:

Java
var age = 25;

because you should first learn Java's type system clearly.


55. Important Boundary Values#

Developers frequently introduce bugs near numeric limits.

Example:

Java
int max = Integer.MAX_VALUE;
System.out.println(max);
System.out.println(max + 1);

Output:

Output
2147483647
-2147483648

Why?

Integer arithmetic can overflow.

Java's ordinary int arithmetic does not automatically throw an exception for this overflow.

The bits wrap according to two's-complement integer arithmetic.

This is very important in production systems handling:

  • counters
  • totals
  • timestamps
  • financial quantities represented as integers
  • large loops

56. Overflow Example#

Java
public class OverflowDemo {
    public static void main(String[] args) {
        int value = Integer.MAX_VALUE;

        System.out.println(value);
        value++;

        System.out.println(value);
    }
}

Output:

Output
2147483647
-2147483648

For overflow-sensitive calculations Java provides methods such as:

Java
Math.addExact(...)

Example:

Java
int result = Math.addExact(Integer.MAX_VALUE, 1);

This throws ArithmeticException instead of silently wrapping.

The broader API is outside this chapter, but the production lesson matters:

Choose a numeric type based on the possible data range, not simply on today's sample data.

57. Narrow Type Assignment#

Consider:

Java
byte value = 100;

This compiles because the constant 100 is within byte range.

But:

Java
int x = 100;
byte value = x;

does not compile without conversion.

Why?

x is an int variable.

At runtime it could potentially contain values outside byte range.

Therefore Java does not automatically narrow it.

Explicit cast:

Java
byte value = (byte) x;

But casting can lose data.

Example:

Java
int x = 130;
byte value = (byte) x;

System.out.println(value);

Output:

Output
-126

So explicit casting should never be treated as a magic "make compiler happy" operation.

It changes how the value is represented.


58. Primitive Numeric Promotion#

Now consider:

Java
byte first = 10;
byte second = 20;

What is the type of:

Java
first + second

Many beginners guess byte.

But Java performs integer numeric promotion.

The result is normally an int.

Therefore:

Java
byte result = first + second;

does not compile.

Correct:

Java
int result = first + second;

Or explicitly cast if you are certain about range:

Java
byte result = (byte) (first + second);

The int form is normally clearer and safer.


59. A Subtle Case: Compound Assignment#

Compare:

Java
byte value = 10;
value = value + 1;

This fails because:

Java
value + 1

is an int.

But:

Java
byte value = 10;
value += 1;

compiles.

Compound assignment includes an implicit conversion equivalent in effect to applying the operator and converting back to the left-hand type.

This is a favorite interview trap.

Do not conclude that += and = with + always have identical typing behavior.


60. char Arithmetic#

Example:

Java
char letter = 'A';
int result = letter + 1;

System.out.println(result);

Output:

Output
66

But:

Java
char next = letter + 1;

does not generally compile because arithmetic promotion produces int.

This works:

Java
char next = (char) (letter + 1);

Output:

Output
B

61. final and Compile-Time Constants#

Consider:

Java
final int value = 100;
byte small = value;

This can compile because value is a compile-time constant whose value fits into byte.

Compare:

Java
int value = 100;
byte small = value;

This does not compile automatically.

That distinction appears in deeper Java interviews.


62. Reference Variables and Object Mutation#

Consider:

Java
class Employee {
    String name;
}

Now:

Java
Employee first = new Employee();
first.name = "Amit";

Employee second = first;
second.name = "Rahul";

System.out.println(first.name);

Output:

Output
Rahul

Why?

first and second refer to the same object.

Diagram:

Output
first ─────┐
           ▼
       ┌──────────────┐
       │ Employee     │
       │ name="Rahul" │
       └──────────────┘
           ▲
second ────┘

Understanding this single diagram will help enormously when you later learn:

  • arrays
  • collections
  • methods
  • mutable objects
  • dependency injection
  • multithreading

63. Reference Reassignment#

Now observe:

Java
Employee first = new Employee();
Employee second = first;

second = new Employee();

After the last statement:

Output
first ─────────► Employee object #1

second ────────► Employee object #2

Reassigning second does not automatically change first.

The variables are separate.

What they previously shared was the same reference value.


64. final Reference vs Immutable Object#

Consider:

Java
final StringBuilder builder = new StringBuilder("Java");

This is forbidden:

Java
builder = new StringBuilder("Python");

But this is legal:

Java
builder.append(" SE");

So remember:

Output
final variable
→ assignment cannot change

immutable object
→ object's observable state cannot be changed after creation

These are different concepts.


65. Real Project Example#

Suppose we are building an order system.

Java
public class Order {
    static int createdOrderCount;

    final long orderId;
    double totalAmount;
    boolean paid;

    Order(long orderId, double totalAmount) {
        this.orderId = orderId;
        this.totalAmount = totalAmount;
        createdOrderCount++;
    }
}

Let us classify the variables.

Output
createdOrderCount
→ static field
→ shared class-level count

orderId
→ instance field
→ final after assignment
→ each Order has its own ID

totalAmount
→ instance field
→ can be updated

paid
→ instance field
→ defaults to false until changed

orderId parameter
→ local parameter variable

totalAmount parameter
→ local parameter variable

This is how variable categories begin to appear naturally inside real Java models.


66. Production Thinking#

Variables look simple, but poor choices here create real production defects.

Choose types according to domain#

Bad reasoning:

Output
Today's user count = 1,000
Therefore byte or short is enough.

Better reasoning:

Output
What is the realistic maximum during the application's lifetime?

Do not use floating point blindly for money#

Risky:

Java
double accountBalance = 0.1 + 0.2;

If exact decimal arithmetic is required, use a suitable exact-decimal strategy such as BigDecimal.


Avoid meaningless mutable globals#

Risky design:

Java
public static int currentValue;

Mutable static state can create:

  • hidden dependencies
  • concurrency problems
  • difficult tests
  • lifecycle confusion

Use static mutable fields only when class-wide mutable state is genuinely appropriate.


Limit variable scope#

Prefer:

Java
if (condition) {
    int retryCount = 3;
}

when the variable is only needed there.

Do not unnecessarily declare it at a much wider scope.

Smaller scope improves:

  • readability
  • correctness
  • maintainability

Initialize variables meaningfully#

Instead of artificially initializing:

Java
int result = 0;

when 0 has no valid business meaning, design the flow so that the variable receives a meaningful value before use.


67. Common Mistakes#

Mistake 1 — Assuming local variables receive defaults#

Risky#

Java
public static void main(String[] args) {
    int count;
    System.out.println(count);
}

Problem#

Compile-time error.

Rule#

Local variables must be definitely assigned before reading.


Mistake 2 — Using double for exact money without understanding precision#

Risk#

Binary floating-point rounding can produce unexpected decimal results.

Better approach#

Use an exact decimal representation when exactness is required.


Mistake 3 — Using == assumptions based on references#

Later, when comparing objects, remember that reference variables introduce different semantics from primitive values.

This chapter gives you the memory model required to understand that topic.


Mistake 4 — Believing final makes an object immutable#

Java
final StringBuilder builder = new StringBuilder();
builder.append("Java");

Legal.

final prevents reference reassignment.

It does not automatically freeze the referenced object.


Mistake 5 — Ignoring overflow#

Java
int count = Integer.MAX_VALUE;
count++;

The result wraps.


Mistake 6 — Accidental octal literal#

Java
int value = 010;

This is decimal 8.


Mistake 7 — Using lowercase l#

Less readable:

Java
long value = 100l;

Preferred:

Java
long value = 100L;

Mistake 8 — Assuming byte arithmetic returns byte#

Java
byte a = 10;
byte b = 20;
byte c = a + b;

Compile-time error.

The arithmetic result is promoted to int.


Mistake 9 — Widening variable scope unnecessarily#

Large scopes make code harder to reason about.

Keep variables as local as reasonably possible.


Mistake 10 — Confusing a reference with the object#

Java
Employee employee = new Employee();

employee is a reference variable.

It is not the object itself.


68. Edge Cases and Traps#

Trap: Maximum integer#

Java
int value = 2_147_483_647;
value++;

Result:

Output
-2147483648

Trap: Float literal#

Invalid:

Java
float value = 3.14;

Correct:

Java
float value = 3.14F;

Trap: char vs String#

Java
char c = 'A';
String s = "A";

These are different types.


Trap: Reference can be null#

Java
String name = null;

Valid declaration.

But:

Java
name.length();

throws NullPointerException.


Trap: Literal constant narrowing#

This can compile:

Java
byte value = 100;

This cannot automatically:

Java
int x = 100;
byte value = x;

Trap: boolean is not numeric#

Invalid:

Java
boolean value = 1;

69. Decision Rules#

Use these practical rules.

Output
Need a normal whole number?
→ int

Need a whole number that may exceed int range?
→ long

Working specifically with raw bytes?
→ byte

Need ordinary decimal floating-point calculations?
→ double

Need reduced-precision floating point for a specific reason?
→ float

Need one UTF-16 code unit?
→ char

Need true/false?
→ boolean

Need an object, array, String, collection, etc.?
→ reference type

For exact money:

Output
Do not choose double merely because the number contains decimals.
Investigate BigDecimal.

70. Complete Revision#

One-line definitions#

Variable: Named storage used to hold a value/reference during execution.

Declaration: Introduces a variable's type and name.

Initialization: First assignment of a value.

Assignment: Stores a right-hand value into a left-hand variable.

Reassignment: Assigning another value after initialization.

Primitive: One of Java's eight basic non-reference types.

Reference variable: Holds a reference value referring to an object/array or null.

Local variable: Variable declared in a local execution context such as a method/block.

Instance variable: Non-static field belonging logically to each object.

Static variable: Class-level field shared at the class level.

Scope: Source-code region where the variable name is accessible.

Lifetime: Runtime period during which the relevant variable/state exists.

Literal: Value written directly in source code.


71. Eight Primitive Types#

Output
byte
short
int
long
float
double
char
boolean

Memory hook:

Output
4 integer
2 floating point
1 character
1 logical

72. Literal Memory Hook#

Output
10        → int-style decimal integer literal
10L       → long
3.14      → double
3.14F     → float
'A'       → char
true      → boolean
0b1010    → binary
012       → octal
0xA       → hexadecimal
1_000_000 → readable numeric literal

73. If You Remember Only 10 Things#

  1. Java variables have a declared type.
  2. Java has exactly eight primitive types.
  3. int is the normal choice for ordinary integers.
  4. Decimal literals are double by default.
  5. float literals normally need F.
  6. Local variables must be assigned before being read.
  7. Instance/static fields receive default values.
  8. Reference assignment copies the reference value, not the object.
  9. final prevents reassignment; it does not guarantee object immutability.
  10. Understand scope, lifetime, stack frames, heap objects, and numeric overflow before writing production Java.

74. Final Knowledge Map#

Output
Variables, Data Types and Memory Basics
│
├── Variable Fundamentals
│   ├── Declaration
│   ├── Initialization
│   ├── Assignment
│   └── Reassignment
│
├── Primitive Types
│   ├── Integer
│   │   ├── byte
│   │   ├── short
│   │   ├── int
│   │   └── long
│   ├── Floating Point
│   │   ├── float
│   │   └── double
│   ├── char
│   └── boolean
│
├── Variable Categories
│   ├── Local
│   ├── Instance
│   ├── Static
│   └── final / constants
│
├── References
│   ├── Object reference
│   ├── null
│   ├── Reference assignment
│   └── final reference
│
├── Memory Model
│   ├── Call stack / frames
│   ├── Heap
│   ├── Object reachability
│   └── Garbage-collection eligibility
│
├── Visibility and Runtime
│   ├── Scope
│   └── Lifetime
│
├── Literals
│   ├── Integer
│   ├── Floating point
│   ├── Character
│   ├── Boolean
│   ├── Binary
│   ├── Octal
│   ├── Hexadecimal
│   └── Numeric underscores
│
└── Important Traps
    ├── Overflow
    ├── Narrowing conversion
    ├── Numeric promotion
    ├── float suffix
    ├── final vs immutability
    ├── local default-value misconception
    └── primitive vs reference assignment

Practice lab

Prove what you just learned