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:
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:
2525 is simply a number.
Similarly:
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:
Variable Name
↓
age
┌───────┐
│ 25 │
└───────┘Here:
ageis the name25is the value
In Java we can write:
int age = 25;Read it naturally:
Create a variable namedagethat can hold anintvalue and initially store25in it.
There are three important pieces:
int age = 25;
│ │ │
│ │ └── value
│ └─────────── variable name
└────────────────── data typeWhy does Java need a data type?#
Consider:
25and:
25.75and:
'A'and:
trueThey 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:
int age = 25;Java knows that age is intended to hold an integer.
Therefore this is invalid:
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.
int age;This is called variable declaration.
The declaration tells Java:
- the variable's type
- the variable's name
Here:
int age;
│ │
│ └── variable name
└────── data typeNo explicit value was assigned in this statement.
General form#
dataType variableName;Examples:
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:
int age;Later we receive the employee's age.
age = 25;The first value assigned to a variable is commonly called its initialization.
We can also declare and initialize together:
int age = 25;Declaration only#
int age;Declaration + initialization#
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:
age = 25;does not mathematically mean:
age equals 25Instead it means:
Evaluate the value on the right side and store that value in the variable on the left side.
Think of the direction:
age = 25
│
└────────► stored into ageAnother example:
int first = 10;
int second = first;Execution:
first = 10
second = first
Java reads first
↓
gets 10
↓
stores 10 into secondNow:
first = 10
second = 10For primitive types, second receives its own primitive value.
6. Variable Reassignment#
Now suppose an employee's salary changes.
double salary = 50000.0;Later:
salary = 55000.0;This is reassignment.
The variable already contained a value and receives another value.
Conceptually:
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:
public class ReassignmentDemo {
public static void main(String[] args) {
int score = 50;
System.out.println(score);
score = 75;
System.out.println(score);
}
}Output:
50
757. One Important Restriction: Type Compatibility#
Once a variable is declared with a type, you cannot arbitrarily change its type.
int age = 25;Later this is valid:
age = 30;But this is not:
age = true;Nor:
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:
byte
short
int
long
float
double
char
booleanPrimitive types represent basic values directly rather than ordinary Java objects.
They fall naturally into four groups:
Primitive Types
│
├── Integer
│ ├── byte
│ ├── short
│ ├── int
│ └── long
│
├── Floating Point
│ ├── float
│ └── double
│
├── Character
│ └── char
│
└── Logical
└── booleanLet 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:
byteA byte is an 8-bit signed integral primitive type.
Range:
-128 to 127Example:
byte level = 100;Valid:
byte temperature = -20;Invalid:
byte value = 128;128 is outside the byte range.
Size#
8 bits = 1 byteTypical 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:
shortSize:
16 bits = 2 bytesRange:
-32,768 to 32,767Example:
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:
intSize:
32 bits = 4 bytesRange:
-2,147,483,648
to
2,147,483,647Example:
int age = 36;
int employeeCount = 5000;
int marks = 85;For integer literals such as:
10
500
100000Java 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:
longSize:
64 bits = 8 bytesRange:
-9,223,372,036,854,775,808
to
9,223,372,036,854,775,807Example:
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.
long population = 8_000_000_000L;Prefer uppercase L.
Although lowercase l is legal:
long number = 100l;it looks dangerously similar to digit 1.
Preferred:
long number = 100L;13. float#
Whole numbers are not enough for many applications.
We may need:
10.5
98.6
3.14Java has two primitive floating-point types.
The smaller is:
floatSize:
32 bits = 4 bytesExample:
float temperature = 36.5F;Why the F?
Because a decimal floating-point literal is double by default.
Therefore this fails:
float temperature = 36.5;Java sees 36.5 as a double.
We need:
float temperature = 36.5F;or:
float temperature = 36.5f;Uppercase or lowercase F is valid.
14. double#
For most general decimal calculations, Java developers normally choose:
doubleSize:
64 bits = 8 bytesExample:
double salary = 75000.50;No suffix is required because decimal literals are double by default.
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:
double price = 10.99;But binary floating-point types cannot represent every decimal fraction exactly.
For example:
public class FloatingPointDemo {
public static void main(String[] args) {
double result = 0.1 + 0.2;
System.out.println(result);
}
}You may see:
0.30000000000000004This 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:
Scientific/general approximate decimal calculations
→ float/double may be appropriate
Exact decimal financial calculation
→ investigate BigDecimal16. char#
Now suppose we need to store a single character.
Java provides:
charExample:
char grade = 'A';Notice single quotes:
'A'A char stores a UTF-16 code unit.
Its size is:
16 bits = 2 bytesIts numeric range is:
0 to 65,535A char is unsigned.
Examples:
char letter = 'J';
char digit = '7';
char symbol = '@';A common beginner mistake is:
char grade = "A";This is invalid because "A" is a String, not a char.
Correct:
char grade = 'A';17. char Is Also Numeric#
This surprises many beginners.
Consider:
char ch = 'A';
System.out.println((int) ch);Output:
65The character 'A' corresponds to numeric value 65.
Because char represents a UTF-16 code unit, numeric operations are possible.
Example:
char ch = 'A';
ch++;
System.out.println(ch);Output:
BThis 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:
Is employee active?
Is payment completed?
Is user authenticated?
Did validation succeed?These are true/false conditions.
Java provides:
booleanA boolean variable holds:
true
falseExample:
boolean active = true;
boolean deleted = false;Unlike some languages, Java does not treat integer 0 and 1 as booleans.
Invalid:
boolean active = 1;Correct:
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#
| Type | Conceptual Java Width | Typical Purpose |
|---|---|---|
byte | 8 bits | Small integers, raw bytes |
short | 16 bits | Small integer range |
int | 32 bits | General integers |
long | 64 bits | Large integers |
float | 32 bits | Single-precision floating point |
double | 64 bits | Double-precision floating point |
char | 16 bits | UTF-16 code unit |
boolean | JVM/language representation not expressed as a fixed numeric width for normal Java semantics | true / false |
20. Primitive Numeric Ranges#
| Type | Minimum | Maximum |
|---|---|---|
byte | -128 | 127 |
short | -32,768 | 32,767 |
int | -2,147,483,648 | 2,147,483,647 |
long | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
char | 0 | 65,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:
float → 32-bit floating point
double → 64-bit floating pointand:
double provides greater precision than float21. 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.
public class Employee {
int age;
boolean active;
}Java supplies default values for fields.
Typical defaults:
| Type | Default |
|---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0D |
char | '\u0000' |
boolean | false |
| Reference type | null |
Example:
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:
0
0.0
false
null22. Local Variables Do NOT Automatically Receive Default Values#
Now suppose the variable is inside a method.
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:
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:
Fields
→ receive default values
Local variables
→ must be assigned before use23. 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:
class Employee {
int age;
static int count;
void print() {
int value = 10;
}
}There are three different categories here:
age → instance variable
count → static variable
value → local variableEach 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:
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:
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.
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.
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:
25
40Mental model:
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.
class Employee {
static int count;
}A static field belongs to the class rather than to each individual object.
Example:
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:
3Conceptually:
Employee class
│
└── count = 3
Objects:
Employee #1
Employee #2
Employee #3All 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:
Employee.countrather than:
employee.countbecause it makes class ownership clear.
27. Local vs Instance vs Static Variables#
| Dimension | Local | Instance | Static |
|---|---|---|---|
| Declared | Inside method/block/constructor | Class body, non-static | Class body with static |
| Belongs to | Current execution scope | Object instance | Class |
| Default value | No usable automatic default before read | Yes | Yes |
| One copy per object? | No | Yes | No |
| Typical access | Direct within scope | Through object / current instance | Usually ClassName.field |
| Lifetime | Related to execution scope | Generally tied to object's reachability/lifetime | Generally 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:
final int maxAttempts = 3;After assignment:
maxAttempts = 5;causes a compile-time error.
29. final Variables#
A final variable can be assigned only once.
Example:
final int age = 25;This is invalid:
age = 30;But there is an important nuance.
final means:
The variable cannot be reassigned after its single assignment.
For primitive variables:
final int value = 10;the primitive value cannot change through reassignment.
For reference variables:
final StringBuilder builder = new StringBuilder("Java");the variable builder cannot be made to refer to another object:
builder = new StringBuilder("Python");Invalid.
But the object itself may still be mutable:
builder.append(" Programming");Valid.
This distinction is critical.
final reference
≠ automatically immutable object30. Constant Naming Convention#
Class constants are commonly written using:
static finalExample:
public class RetryConfig {
public static final int MAX_RETRY_COUNT = 3;
}Naming convention:
UPPER_SNAKE_CASEExamples:
MAX_RETRY_COUNT
DEFAULT_PORT
SECONDS_PER_MINUTEThis is a convention, not a special compiler rule.
31. Reference Variables#
So far primitive variables have been relatively simple.
int age = 25;But what happens here?
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:
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:
nullExample:
Employee employee = null;That means it currently refers to no object.
If we then attempt:
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#
int age = 25;age directly represents the primitive value 25.
Reference#
Employee employee = new Employee();employee stores a reference value referring to an object.
Comparison:
| Dimension | Primitive | Reference |
|---|---|---|
| Examples | int, double, char, boolean | String, arrays, custom classes |
| Holds | Primitive value | Reference value |
Can be null | No | Yes |
| Object required | No | Usually refers to object/array |
| Built-in primitive types | Exactly 8 | Huge number of reference types |
| Methods directly defined on primitive value | No object methods | Referenced objects can provide methods |
34. Primitive Assignment vs Reference Assignment#
This is extremely important.
Primitive assignment#
int first = 10;
int second = first;
second = 20;
System.out.println(first);
System.out.println(second);Output:
10
20Why?
second received a copy of the primitive value.
Conceptually:
first = 10
second = 10Then:
second = 20does not affect first.
35. Reference Assignment#
Now consider:
StringBuilder first = new StringBuilder("Java");
StringBuilder second = first;
second.append(" SE");
System.out.println(first);
System.out.println(second);Output:
Java SE
Java SEWhy?
Both variables refer to the same mutable object.
Conceptually:
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:
public static void main(String[] args) {
int age = 25;
calculate();
}
static void calculate() {
int value = 10;
}Conceptual flow:
main() called
Call Stack
┌───────────────┐
│ main frame │
│ age = 25 │
└───────────────┘Then calculate() is called:
Call Stack
┌───────────────┐
│ calculate │
│ value = 10 │
├───────────────┤
│ main │
│ age = 25 │
└───────────────┘When calculate() returns:
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:
new Employee()are normally associated with heap allocation in the standard JVM mental model.
Example:
Employee employee = new Employee();Conceptually:
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#
| Dimension | Stack / Call Stack Model | Heap Model |
|---|---|---|
| Main purpose | Method execution frames | Objects and arrays |
| Lifetime | Often tied to method invocation | Depends on object reachability |
| Management | Frames pushed/popped with calls | Managed with garbage collection |
| Common failure | StackOverflowError | OutOfMemoryError scenarios |
| Access pattern | Execution-oriented | Object-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:
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:
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.
{
int value = 10;
}Outside that block:
System.out.println(value);value is not accessible.
Example:
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:
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#
| Question | Scope | Lifetime |
|---|---|---|
| Concern | Source-code visibility | Runtime existence |
| Main question | "Can I access this name here?" | "How long does this state exist?" |
| Example | Local block boundaries | Method call/object/class lifecycle |
This distinction is frequently asked in interviews.
44. Literals#
Until now we have written values directly:
10
3.14
'A'
trueValues written directly in source code are called literals.
Examples:
int count = 10;
double price = 99.50;
char grade = 'A';
boolean active = true;Here:
10 → integer literal
99.50 → floating-point literal
'A' → character literal
true → boolean literalJava supports several useful literal forms.
45. Integer Literals#
Basic decimal integer:
int value = 100;Negative value:
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:
double price = 10.5;
double scientific = 1.2e3;
float temperature = 36.5F;1.2e3 means:
1.2 × 10³
= 1200.0Example:
System.out.println(1.2e3);Output:
1200.047. Character Literals#
Character literals use single quotes:
char grade = 'A';Escape characters are also possible.
Examples:
char newline = '\n';
char tab = '\t';
char quote = '\'';
char backslash = '\\';Unicode escape form:
char letter = '\u0041';\u0041 represents A.
48. Boolean Literals#
Java provides exactly two boolean literal values:
true
falseExample:
boolean loggedIn = true;
boolean deleted = false;They are keywords and are written lowercase.
Invalid:
boolean value = True;Correct:
boolean value = true;49. Binary Literals#
Sometimes developers need to work directly with bit patterns.
Binary uses digits:
0 and 1Java allows binary literals with prefix:
0bor:
0BExample:
int value = 0b1010;
System.out.println(value);Output:
10Because:
1010₂ = 10₁₀50. Octal Literals#
Octal uses base 8.
Java indicates an octal integer literal with a leading 0.
Example:
int value = 012;
System.out.println(value);Output:
10Why?
12₈ = 10₁₀Common production warning#
Leading zeroes can confuse readers.
Example:
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:
0-9
A-FPrefix:
0xor:
0XExample:
int value = 0xFF;
System.out.println(value);Output:
255Hexadecimal 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:
int decimal = 10;
int binary = 0b1010;
int octal = 012;
int hexadecimal = 0xA;All represent numeric value 10.
System.out.println(decimal);
System.out.println(binary);
System.out.println(octal);
System.out.println(hexadecimal);Output:
10
10
10
1053. Underscores in Numeric Literals#
Large numbers can become difficult to read.
Compare:
int salary = 1000000;with:
int salary = 1_000_000;The underscore improves readability.
Java ignores permitted numeric-literal underscores when evaluating the numeric value.
long accountNumberPart = 123_456_789L;The value is still:
123456789Valid examples#
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:
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:
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:
int age = 25;rather than:
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:
int max = Integer.MAX_VALUE;
System.out.println(max);
System.out.println(max + 1);Output:
2147483647
-2147483648Why?
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#
public class OverflowDemo {
public static void main(String[] args) {
int value = Integer.MAX_VALUE;
System.out.println(value);
value++;
System.out.println(value);
}
}Output:
2147483647
-2147483648For overflow-sensitive calculations Java provides methods such as:
Math.addExact(...)Example:
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:
byte value = 100;This compiles because the constant 100 is within byte range.
But:
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:
byte value = (byte) x;But casting can lose data.
Example:
int x = 130;
byte value = (byte) x;
System.out.println(value);Output:
-126So 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:
byte first = 10;
byte second = 20;What is the type of:
first + secondMany beginners guess byte.
But Java performs integer numeric promotion.
The result is normally an int.
Therefore:
byte result = first + second;does not compile.
Correct:
int result = first + second;Or explicitly cast if you are certain about range:
byte result = (byte) (first + second);The int form is normally clearer and safer.
59. A Subtle Case: Compound Assignment#
Compare:
byte value = 10;
value = value + 1;This fails because:
value + 1is an int.
But:
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:
char letter = 'A';
int result = letter + 1;
System.out.println(result);Output:
66But:
char next = letter + 1;does not generally compile because arithmetic promotion produces int.
This works:
char next = (char) (letter + 1);Output:
B61. final and Compile-Time Constants#
Consider:
final int value = 100;
byte small = value;This can compile because value is a compile-time constant whose value fits into byte.
Compare:
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:
class Employee {
String name;
}Now:
Employee first = new Employee();
first.name = "Amit";
Employee second = first;
second.name = "Rahul";
System.out.println(first.name);Output:
RahulWhy?
first and second refer to the same object.
Diagram:
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:
Employee first = new Employee();
Employee second = first;
second = new Employee();After the last statement:
first ─────────► Employee object #1
second ────────► Employee object #2Reassigning 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:
final StringBuilder builder = new StringBuilder("Java");This is forbidden:
builder = new StringBuilder("Python");But this is legal:
builder.append(" SE");So remember:
final variable
→ assignment cannot change
immutable object
→ object's observable state cannot be changed after creationThese are different concepts.
65. Real Project Example#
Suppose we are building an order system.
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.
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 variableThis 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:
Today's user count = 1,000
Therefore byte or short is enough.Better reasoning:
What is the realistic maximum during the application's lifetime?Do not use floating point blindly for money#
Risky:
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:
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:
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:
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#
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#
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#
int count = Integer.MAX_VALUE;
count++;The result wraps.
Mistake 6 — Accidental octal literal#
int value = 010;This is decimal 8.
Mistake 7 — Using lowercase l#
Less readable:
long value = 100l;Preferred:
long value = 100L;Mistake 8 — Assuming byte arithmetic returns byte#
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#
Employee employee = new Employee();employee is a reference variable.
It is not the object itself.
68. Edge Cases and Traps#
Trap: Maximum integer#
int value = 2_147_483_647;
value++;Result:
-2147483648Trap: Float literal#
Invalid:
float value = 3.14;Correct:
float value = 3.14F;Trap: char vs String#
char c = 'A';
String s = "A";These are different types.
Trap: Reference can be null#
String name = null;Valid declaration.
But:
name.length();throws NullPointerException.
Trap: Literal constant narrowing#
This can compile:
byte value = 100;This cannot automatically:
int x = 100;
byte value = x;Trap: boolean is not numeric#
Invalid:
boolean value = 1;69. Decision Rules#
Use these practical rules.
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 typeFor exact money:
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#
byte
short
int
long
float
double
char
booleanMemory hook:
4 integer
2 floating point
1 character
1 logical72. Literal Memory Hook#
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 literal73. If You Remember Only 10 Things#
- Java variables have a declared type.
- Java has exactly eight primitive types.
intis the normal choice for ordinary integers.- Decimal literals are
doubleby default. floatliterals normally needF.- Local variables must be assigned before being read.
- Instance/static fields receive default values.
- Reference assignment copies the reference value, not the object.
finalprevents reassignment; it does not guarantee object immutability.- Understand scope, lifetime, stack frames, heap objects, and numeric overflow before writing production Java.
74. Final Knowledge Map#
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