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 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; |
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;
These include String, arrays, classes, interfaces, etc. They store the memory
address of the object, not the actual value.
String name = "Java Learner";
int[] numbers = {1, 2, 3, 4};
Syntax: type variableName = value;
int age = 25;
double height = 5.9;
String language = "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 |
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.
Java uses a managed memory model with two primary regions:
| ๐น 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 stackname is a reference in the stack, pointing to the string
"Java" in the heap
| ๐น 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 stacknew 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!
Smaller type to larger type โ safe.
int x = 10;
double y = x; // implicit cast int โ double
Larger type to smaller โ risky if out of bounds.
double pi = 3.14159;
int approx = (int) pi; // 3
Java does not throw an error if integers overflow โ they wrap around.
int max = Integer.MAX_VALUE;
System.out.println(max + 1); // Output: -2147483648
Type casting means converting one data type into another. In Java, there are two kinds:
| 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.
double value = 5.99;
int result = (int) value;
System.out.println(result); // 5
โ Explanation: Truncates the decimal, does NOT round
โ Expected Mistakes:
int result = value; โ Compile errorint 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.
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.256 (the total number of values in a byte) from 130 to get
-126.
-128 to 127.127, you loop back to the negative side.128 โ -128129 โ -127130 โ -126// Manual Wrap Around Logic
int wrapped = 130 - 256; // byte can hold 256 values total
System.out.println(wrapped); // Output: -126
0 โ positive1 โ negativeโ ๏ธ 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.
float f = 7.5f;
int x = (int) f;
System.out.println(x);
โ
Output: 7
โ Mistake: Assuming it will round to 8
| 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; |
Java allows converting between data types using type casting. It happens in two ways:
// 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!
// 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:
int x = d; โ Error7.99 โ 8 โfloat to intfloat f = 9.8f;
int i = (int) f;
System.out.println(i); // Output: 9
char โ intchar c = 'Z';
int ascii = c;
System.out.println(ascii); // Output: 90
int โ byteint num = 258;
byte b = (byte) num;
System.out.println(b); // Output: 2
โ Because 258 - 256 = 2 (wrapped around)
double to int?double val = 6.9999;
int n = (int) val;
System.out.println(n); // Output: 6
byte a = 50;
int x = a; // implicit
float f = x; // implicit
int back = (int) f; // explicit
System.out.println(back); // Output: 50
| 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!
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.
byte Overflowbyte b = (byte) 130;
System.out.println(b); // Output: -126
โ
Explanation:
byte range is -128 to 127 (8-bit signed)short Overflowshort s = (short) 40000;
System.out.println(s); // Output: -25536
โ
Explanation:
short range is -32,768 to 32,767 (16-bit signed)int Overflowint x = Integer.MAX_VALUE; // 2,147,483,647
x = x + 1;
System.out.println(x); // Output: -2147483648
โ
Explanation:
int range is -231 to 231-1long Overflowlong 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-1char Overflowchar c = 65535; // max char value
c++;
System.out.println((int) c); // Output: 0
โ
Explanation:
char is an unsigned 16-bit type โ range 0 to 65535char with signed numbers โ it's always positivefloat Overflowfloat f = Float.MAX_VALUE;
f = f * 100;
System.out.println(f); // Output: Infinity
โ
Explanation:
float max value is approx 3.4 ร 1038InfinityInfinitydouble Overflowdouble d = Double.MAX_VALUE;
d = d * 2;
System.out.println(d); // Output: Infinity
โ
Explanation:
double max value is approx 1.8 ร 10308InfinityInfinityboolean (No Overflow)boolean b = true;
b = !b;
System.out.println(b); // Output: false
โ
Explanation:
boolean only stores true or false1 or 0 โ Java won't allow it| 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 |
โ
Always check ranges using constants like Byte.MAX_VALUE,
Integer.MIN_VALUE, etc., before performing casts or calculations to prevent unexpected overflows.
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.
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.
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.
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.
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.
finalfinal to make variables constant.final locks the reference, not the object's content.PI, GRAVITY, etc.double value (7.9) to int. What do you get?char.int input and shows if it's within the byte range
(-128 to 127).int to double.String firstName and lastName โ print the full name.final double PI = 3.14159.
int and prints the result.int instead of double for decimal values.float literals โ e.g., float x = 3.14f;char and String โ 'A' vs "A"
byte or short accidentally.final variables โ it's not allowed.finalString 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.float or int for GPA, which may lose precision.; at the end of statements.System.out.println.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).char.
char letter = 'J';
System.out.println("Favorite character: " + letter);
โ
Explanation: char stores a single character surrounded by single quotes."J") โ which is a String, not a char.
'Java' in a char.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.=< instead of <=.java.util.Scanner.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.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.AelifyGitHub.
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.Math.pow(radius, 2) incorrectly or unnecessarily for simple squaring.final.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.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)
๐ Documentation Index