🧮 [4] Data Types & Variables — The Core Foundation of Java!

🧮 [4] Data Types & Variables — The Core Foundation of Java!

🧮 [4] Data Types & Variables — The Core Foundation of Java!

✨ Introduction

Data types are the DNA of Java. Every variable you use — whether a number, letter, sentence, or boolean — has a type. Java is a statically-typed language, meaning every variable must have a type defined at compile time.

This post will teach you everything from simple int values to complex memory behavior behind the scenes. If you're ready to go from beginner to confident coder, let's dive deep.

🔢 Java Data Types Overview

🧱 Primitive Types (8 total)

Java has 8 built-in (primitive) data types:

Type Size Default Max Value Example
byte 1 byte 0 127 byte b = 100;
short 2 bytes 0 32,767 short s = 10000;
int 4 bytes 0 2,147,483,647 int x = 42;
long 8 bytes 0L 9,223,372,036,854,775,807 long l = 123456789L;
float 4 bytes 0.0f ~3.4e+38 float pi = 3.14f;
double 8 bytes 0.0 ~1.7e+308 double d = 9.81;
char 2 bytes '\u0000' 65,535 (unsigned) char c = 'A';
boolean 1 bit (logical) false true / false only boolean isOn = true;

🧪 Example:

byte a = 127;
short b = 32000;
int c = 100000;
long d = 123456789L;

float e = 5.75f;
double f = 19.99;

char grade = 'A';
boolean isJavaFun = true;

🧠 Reference Data Types

These include String, arrays, classes, interfaces, etc. They store the memory address of the object, not the actual value.

Example:

String name = "Java Learner";
int[] numbers = {1, 2, 3, 4};

📦 Variable Declaration

Syntax: type variableName = value;

🧪 Example:

int age = 25;
double height = 5.9;
String language = "Java";

🔍 Primitive vs Reference Types in Java

Feature Primitive Type Reference Type
Definition Basic data types that store actual values Objects that store references (addresses) to memory locations
Stored Value The actual data (like number, character) A reference (or pointer) to the actual object in heap memory
Examples int, float, boolean, char, byte, short, long, double String, Arrays, Classes, Scanner, List, etc.
Memory Location Stored on the stack Reference is on stack, actual object is on the heap
Default Value Depends on type (e.g., int = 0, boolean = false) null
Mutability Immutable — you create new values when changing Objects can be mutable or immutable depending on class
Operations Basic arithmetic and logical operations directly apply Use methods or functions (e.g., str.length())
Comparison Compared using == (value comparison) Use .equals() for content; == compares reference
Wrapper Classes Yes — int → Integer, double → Double Already objects — no need for wrappers
Garbage Collection Not applicable — primitive variables are automatically cleaned Yes — handled by Java Garbage Collector for unused objects

💡 Summary

Use primitive types for efficiency and simple value storage (like numbers, booleans).

Use reference types when working with objects, data structures, and more complex data.

🧠 Memory in Java — Stack vs Heap

Java uses a managed memory model with two primary regions:

✅ 1. Stack Memory

🔹 Feature 🔹 Description
📦 Stores Method calls, local variables, references
🧠 Location Each thread has its own stack
⚡ Fast? Very fast — grows/shrinks with method calls
🔐 Access Automatically managed — pops off when method ends

Example:

public class MemoryDemo {
    public static void main(String[] args) {
        int x = 10;              // x lives in the stack
        String name = "Java";    // reference in stack, object in heap
    }
}
  • 🧠 x is stored directly in the stack
  • 📍 name is a reference in the stack, pointing to the string "Java" in the heap

✅ 2. Heap Memory

🔹 Feature 🔹 Description
📦 Stores All objects and class instances
🧠 Shared? Yes, shared across all threads
♻️ GC Managed Yes — cleaned by Garbage Collector
🐢 Speed Slower access than stack

Example:

class Person {
    String name;
}

public class HeapExample {
    public static void main(String[] args) {
        Person p1 = new Person();     // p1 → reference in stack
        p1.name = "Aelify";           // Object stored in heap

        System.out.println("Person's name is: " + p1.name);
    }
}

/*
          +---------------------+
          |    Stack Memory     |
          +---------------------+
          |  p1 (ref to Person) | -----------+
          +---------------------+            |
                                             v
                             +-----------------------------+
                             |         Heap Memory         |
                             +-----------------------------+
                             |  Person object              |
                             |  +-----------------------+  |
                             |  | name --> "Aelify"     |  |
                             |  +-----------------------+  |
                             +-----------------------------+

Notes:
- p1 is a local variable stored on the stack.
- The Person object is created on the heap.
- The 'name' field inside Person is a reference to another object ("Aelify") also in the heap.
*/

Output:

Person's name is: Aelify
  • p1 is in the stack
  • new Person() object is in the heap

Explanation: In Java, local variables like p1 are stored in the stack, but the actual Person object is created in the heap. The variable p1 holds the reference to the heap memory.

Expected Mistake: Beginners often think the entire object is in the stack — but only the reference is!

⚠️ Common Mistakes

  • ❌ Thinking all variables are stored in the same place
  • ❌ Misunderstanding how references work (e.g., copying references just copies the address, not the object)
  • ❌ Forgetting about Garbage Collection — heap objects are auto-deleted if unused

🔄 Type Casting in Java

👉 Implicit Casting (Widening)

Smaller type to larger type — safe.

int x = 10;
double y = x; // implicit cast int → double

👉 Explicit Casting (Narrowing)

Larger type to smaller — risky if out of bounds.

double pi = 3.14159;
int approx = (int) pi; // 3

📉 Overflow & Underflow

Java does not throw an error if integers overflow — they wrap around.

int max = Integer.MAX_VALUE;
System.out.println(max + 1); // Output: -2147483648

🔹 What is Type Casting?

Type casting means converting one data type into another. In Java, there are two kinds:

✅ 1. Implicit Casting (Widening Conversion)

  • ✔️ Done automatically by Java
  • ✔️ Happens when converting smaller → larger types
From To
byte short, int, long, float, double
int long, float, double
int x = 100;
double y = x; // Implicit casting
System.out.println(y); // 100.0

Explanation: Java automatically converts int to double without loss.

Expected Mistake: Thinking it will behave differently or cause rounding — it won’t.

✅ 2. Explicit Casting (Narrowing Conversion)

  • ❌ Not automatic
  • ❌ You must use manual cast syntax
double value = 5.99;
int result = (int) value;
System.out.println(result); // 5

Explanation: Truncates the decimal, does NOT round

Expected Mistakes:

  • Forgetting parentheses: int result = value; → Compile error
  • Expecting 6 as output due to rounding

✅ Overflow Example:

int big = 130;
byte b = (byte) big;

System.out.println(b); // Output: -126

Explanation: byte max = 127

130 causes overflow:

130 - 256 = -126 due to 2’s complement wrapping.

✅ Overflow Example (Beginner-Friendly Explanation 😄)

int big = 130;
byte b = (byte) big;

System.out.println("After casting: " + b); // Output: After casting: -126

Explanation: Java uses 2's complement binary format to store negative numbers in byte-sized containers.

  • byte holds values between -128 and 127.
  • 130 is too big for a byte, so Java wraps it around.
  • It subtracts 256 (the total number of values in a byte) from 130 to get -126.

🔍 How It Works (Visually)

  • Imagine a circle with numbers from -128 to 127.
  • If you move past 127, you loop back to the negative side.
  • Example overflow steps:
    • 128 → -128
    • 129 → -127
    • 130 → -126
// Manual Wrap Around Logic
int wrapped = 130 - 256; // byte can hold 256 values total
System.out.println(wrapped); // Output: -126

🔢 What Is 2's Complement?

  • It’s how computers store negative numbers in binary.
  • The leftmost bit (most significant bit) indicates the sign:
    • 0 → positive
    • 1 → negative
  • When overflow happens, the binary rolls over like a digital counter, flipping bits.

⚠️ Expected Mistake: Many assume Java will throw an error or round the number — it doesn’t. It silently wraps.

Important: Always check value ranges before casting to smaller types like byte or short.

🧠 Mini Practice

float f = 7.5f;
int x = (int) f;
System.out.println(x);

✅ Output: 7

❌ Mistake: Assuming it will round to 8

🔬 Summary Table: Type Casting

Casting Type Automatic? Direction Risk of Data Loss? Syntax
Implicit (Widening) ✅ Yes Smaller → Larger ❌ No double d = intVal;
Explicit (Narrowing) ❌ No Larger → Smaller ✅ Yes int i = (int) 5.9;

🔄 Type Casting Examples in Java

Java allows converting between data types using type casting. It happens in two ways:

  • Implicit Casting (Widening) — ✅ safe, automatic
  • Explicit Casting (Narrowing) — ❌ risky, manual

✅ Implicit Casting Examples (Automatic)

// byte → int
byte b = 10;
int num = b;
System.out.println(num); // 10

// int → double
int marks = 85;
double result = marks;
System.out.println(result); // 85.0

// char → int
char ch = 'A';
int ascii = ch;
System.out.println(ascii); // 65

⚠️ Common Mistake: Expecting int → float to lose precision. It doesn’t!

❌ Explicit Casting Examples (Manual)

// double → int (Truncates decimals)
double d = 7.99;
int x = (int) d;
System.out.println(x); // 7

// int → byte (Risk of overflow!)
int big = 130;
byte small = (byte) big;
System.out.println(small); // -126

// long → short
long population = 30000L;
short popShort = (short) population;
System.out.println(popShort); // 30000 (✅ fits safely)

// float → int
float pi = 3.14f;
int intPi = (int) pi;
System.out.println(intPi); // 3

// char → byte
char c = 'B'; // 66
byte bc = (byte) c;
System.out.println(bc); // 66

⚠️ Expected Mistakes:

  • Forgetting parentheses: int x = d; ❌ Error
  • Thinking casting rounds instead of truncates: 7.99 → 8 ❌
  • Not checking overflow when casting large numbers

🧪 Practice + Answers

🔹 Q1. Cast a float to int

float f = 9.8f;
int i = (int) f;
System.out.println(i); // Output: 9

🔹 Q2. Implicit cast char → int

char c = 'Z';
int ascii = c;
System.out.println(ascii); // Output: 90

🔹 Q3. Overflow example: int → byte

int num = 258;
byte b = (byte) num;
System.out.println(b); // Output: 2

✅ Because 258 - 256 = 2 (wrapped around)

🔹 Q4. What happens when you cast double to int?

double val = 6.9999;
int n = (int) val;
System.out.println(n); // Output: 6

🔹 Q5. Combine implicit and explicit casts

byte a = 50;
int x = a;       // implicit
float f = x;     // implicit
int back = (int) f;  // explicit
System.out.println(back); // Output: 50

📌 Summary Table — Casting Overview

From To Type Syntax Risk
int double Implicit double d = i; No
double int Explicit int i = (int) d; Yes
char int Implicit int i = c; No
int byte Explicit byte b = (byte) i; Yes

Reminder: Use explicit casting carefully — always check the range of your destination type!

💥 Overflow in Java — All Primitive Types (Full Explanation)

In Java, overflow happens when a value goes beyond the range of a primitive type. For integer types, Java silently wraps the value using 2's complement logic. For floating-point types, it becomes Infinity.

1️⃣ byte Overflow

byte b = (byte) 130;
System.out.println(b); // Output: -126
Explanation:
  • byte range is -128 to 127 (8-bit signed)
  • 130 - 256 = -126 → wraps around using 2's complement
Expected Mistake:
  • Beginners expect an error or rounding — Java wraps it silently

2️⃣ short Overflow

short s = (short) 40000;
System.out.println(s); // Output: -25536
Explanation:
  • short range is -32,768 to 32,767 (16-bit signed)
  • 40000 - 65536 = -25536 (65536 = 216)
Expected Mistake:
  • People assume short can handle any 5-digit number — not always true

3️⃣ int Overflow

int x = Integer.MAX_VALUE; // 2,147,483,647
x = x + 1;
System.out.println(x); // Output: -2147483648
Explanation:
  • int range is -231 to 231-1
  • Adding 1 to max value wraps around to the negative side
Expected Mistake:
  • Assuming Java throws an error — it just wraps around

4️⃣ long Overflow

long l = Long.MAX_VALUE; // 9,223,372,036,854,775,807
l = l + 1;
System.out.println(l); // Output: -9223372036854775808
Explanation:
  • long range is -263 to 263-1
  • It wraps to minimum value after overflow
Expected Mistake:
  • Assuming large numbers like this are safe — overflow still happens

5️⃣ char Overflow

char c = 65535; // max char value
c++;
System.out.println((int) c); // Output: 0
Explanation:
  • char is an unsigned 16-bit type → range 0 to 65535
  • Adding 1 wraps it back to 0
Expected Mistake:
  • People confuse char with signed numbers — it’s always positive

6️⃣ float Overflow

float f = Float.MAX_VALUE;
f = f * 100;
System.out.println(f); // Output: Infinity
Explanation:
  • float max value is approx 3.4 × 1038
  • When exceeded, it turns into Infinity
Expected Mistake:
  • People expect float to wrap or clamp — but it just becomes Infinity

7️⃣ double Overflow

double d = Double.MAX_VALUE;
d = d * 2;
System.out.println(d); // Output: Infinity
Explanation:
  • double max value is approx 1.8 × 10308
  • Exceeding it results in Infinity
Expected Mistake:
  • Expecting it to crash — Java just prints Infinity

8️⃣ boolean (No Overflow)

boolean b = true;
b = !b;
System.out.println(b); // Output: false
Explanation:
  • boolean only stores true or false
  • It cannot overflow — any attempt to assign numbers gives a compile-time error
Expected Mistake:
  • Trying to assign integers like 1 or 0 → Java won't allow it

📘 Summary Table

Type Min Max Overflow Result
byte -128 127 Wraps to -128 → up
short -32,768 32,767 Wraps to -32,768 → up
int -231 231 - 1 Wraps to negative
long -263 263 - 1 Wraps to negative
char 0 65,535 Wraps to 0
float ~ -3.4×1038 ~ 3.4×1038 Infinity
double ~ -1.8×10308 ~ 1.8×10308 Infinity
boolean false true No overflow

🎯 Final Tip

Always check ranges using constants like Byte.MAX_VALUE, Integer.MIN_VALUE, etc., before performing casts or calculations to prevent unexpected overflows.

📌 Final Keyword (Constants)

Use final in Java to create constants — values that cannot be changed after initialization.

final double GRAVITY = 9.8;

Explanation: The keyword final locks the variable. Once you assign a value, you can’t change it later. Trying to do so will cause a compile-time error.

🧪 Example 1: Basic Constant

Q: Can I change the value of a final variable after assigning it?

final int SPEED_LIMIT = 60;
System.out.println("Speed limit: " + SPEED_LIMIT);
SPEED_LIMIT = 80; // ❌ Error: cannot assign a value to final variable

Explanation: Once SPEED_LIMIT is set to 60, it’s locked. The reassignment to 80 is illegal.

Expected Mistake: Trying to reassign a final variable.

🧪 Example 2: Final with Objects

Q: Can I change the internal state of a final object?

final StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Output: Hello World

Explanation: You can't reassign sb to a new object, but you can modify its content.

Expected Mistake: Thinking final makes objects fully unchangeable. It only protects the reference, not the object itself.

🧪 Example 3: Final Parameters

Q: What happens if I declare a method parameter as final?

public class FinalParameterExample {
    
    public static void main(String[] args) {
        greet("Aelify");
    }

    static void greet(final String name) {
        // name = "GitHub"; // ❌ Error: cannot assign a value to final parameter
        System.out.println("Hello, " + name);
    }
}

Explanation: The name parameter is marked as final, which means it cannot be reassigned within the method. This is useful for protecting input arguments from accidental changes.

Expected Mistake: Trying to reassign the parameter (e.g. name = "GitHub";) will result in a compile-time error.

🧪 Example 4: Final with Loops

Q: Can I use final in a loop variable?

for (final int i = 0; i < 3; i++) {
    System.out.println(i); // ❌ Error: cannot assign a value to final variable
}

Explanation: Since loop counters are modified on each iteration, they can’t be final. This will throw a compile-time error.

Expected Mistake: Using final for variables that must change in a loop.

📌 Summary of final

  • ✅ Use final to make variables constant.
  • 🛡️ Final variables can be initialized once — no reassignment allowed.
  • 🧠 With objects, final locks the reference, not the object's content.
  • 📦 Useful for constants like PI, GRAVITY, etc.

🧠 Exercises — Practice Time!

💡 Beginner

  • Declare variables for name, age, and GPA. Print them.
  • Cast a double value (7.9) to int. What do you get?
  • Store your favorite character in a char.

🧪 Intermediate

  • Write a program that takes an int input and shows if it's within the byte range (-128 to 127).
  • Demonstrate implicit casting by assigning int to double.
  • Create two variables: String firstName and lastName — print the full name.

🔥 Challenge

  • Create a program to calculate the area of a circle given radius. Use final double PI = 3.14159.
  • Write a program that causes overflow in an int and prints the result.

⚠️ Common Mistakes

  • Using int instead of double for decimal values.
  • Forgetting 'f' in float literals — e.g., float x = 3.14f;
  • Mixing char and String'A' vs "A"
  • Overflowing byte or short accidentally.
  • Trying to modify final variables — it’s not allowed.
  • Expecting compiler to warn about overflow — it won’t.
  • Using undeclared variables
  • Declaring variables inside condition or loop, then trying to use them outside

✅ Recap

  • Primitive vs Reference data types
  • Memory size and default values
  • Type casting (safe vs risky)
  • Overflow and memory behavior
  • Constants with final

🧠 Answers — Practice Time (with Explanations)

💡 Beginner

  1. Declare variables for name, age, and GPA. Print them.
    String name = "Aelify";
    int age = 20;
    double gpa = 3.8;
    
    System.out.println("Name: " + name);
    System.out.println("Age: " + age);
    System.out.println("GPA: " + gpa);
    Explanation: Basic variable declaration uses appropriate data types: String, int, and double.
    Expected Mistakes:
    • Using float or int for GPA, which may lose precision.
    • Missing ; at the end of statements.
    • Misspelling System.out.println.
  2. Cast a double value (7.9) to int. What do you get?
    double value = 7.9;
    int result = (int) value;
    
    System.out.println("Casted value: " + result); // Output: 7
    Explanation: Casting a double to int truncates the decimal (no rounding).
    Expected Mistake: Assuming the result will be 8 due to rounding.
  3. Store your favorite character in a char.
    char letter = 'J';
    System.out.println("Favorite character: " + letter);
    Explanation: char stores a single character surrounded by single quotes.
    Expected Mistakes:
    • Using double quotes ("J") — which is a String, not a char.
    • Trying to store multiple characters like 'Java' in a char.

🧪 Intermediate

  1. Check if input int is within byte range:
    import java.util.Scanner;
    
    public class ByteCheck {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            System.out.print("Enter an integer: ");
            int num = sc.nextInt();
    
            if (num >= -128 && num <= 127) {
                System.out.println("This number fits in a byte.");
            } else {
                System.out.println("This number does NOT fit in a byte.");
            }
            
            sc.close();
        }
    }
    
    Explanation: A byte can hold values from -128 to 127. This checks that range.
    Expected Mistakes:
    • Using incorrect operators like =< instead of <=.
    • Forgetting to import java.util.Scanner.
  2. Implicit casting from int to double:
    int a = 42;
    double b = a;
    
    System.out.println("Double value: " + b);
    Explanation: Java automatically casts smaller types (int) to larger types (double) without explicit syntax.
    Expected Mistake: Trying to manually cast when not needed or thinking it's an error.
  3. Print full name using two String variables:
    String firstName = "Aelify";
    String lastName = "GitHub";
    
    System.out.println("Full Name: " + firstName + " " + lastName);
    Explanation: Use + for string concatenation, and don’t forget the space between names.
    Expected Mistake: Omitting the space, resulting in output like AelifyGitHub.

🔥 Challenge

  1. Calculate area of a circle using final double PI:
    import java.util.Scanner;
    
    public class CircleArea {
        public static void main(String[] args) {
            final double PI = 3.14159;
    
            Scanner sc = new Scanner(System.in);
            System.out.print("Enter radius: ");
            double radius = sc.nextDouble();
    
            double area = PI * radius * radius;
            System.out.println("Area of circle: " + area);
    
            sc.close();
        }
    }
    
    import java.util.Scanner;
    
    public class CircleAreaUsingMathPow {
        public static void main(String[] args) {
            final double PI = 3.14159;
    
            Scanner sc = new Scanner(System.in);
            System.out.print("Enter radius: ");
            double radius = sc.nextDouble();
    
            double area = PI * Math.pow(radius, 2);
            System.out.println("Area of circle: " + area);
    
            sc.close();
        }
    }
    
    import java.util.Scanner;
    
    public class CircleAreaRounded {
        public static void main(String[] args) {
            final double PI = 3.14159;
    
            Scanner sc = new Scanner(System.in);
            System.out.print("Enter radius: ");
            double radius = sc.nextDouble();
    
            double area = PI * radius * radius;
    
            // Round to 2 decimal places
            String roundedArea = String.format("%.2f", area);
            System.out.println("Area of circle: " + roundedArea);
    
            sc.close();
        }
    }
    
    Explanation: final makes PI a constant, and radius * radius is squaring.
    Expected Mistakes:
    • Using Math.pow(radius, 2) incorrectly or unnecessarily for simple squaring.
    • Forgetting to declare PI or not marking it as final.
  2. Cause overflow in int and print result:
    int max = Integer.MAX_VALUE;
    System.out.println("Before Overflow: " + max); // Before Overflow: 2147483647
    System.out.println("After Overflow: " + (max + 1)); // After Overflow: -2147483648
    Explanation: Java doesn't raise an error for overflow — it wraps to the negative range.
    Expected Mistake: Thinking Java will stop or throw an exception — it won't!

You’ve now mastered how Java handles data at the core level. This is the foundation for everything to come, especially logic-heavy tasks, conditions, OOP, and collections.

In our next post, we'll dive into 🔧 [5] Operators & Control Flow — Decision Making in Java!

— Blog by Aelify (ML2AI.com)