Data types define what kind of value a variable can store and what operations Java allows on that value. Java is strongly typed, so every variable, parameter, field, and return value has a type known at compile time.
Core Java data types are usually learned in two groups: primitive types, which store simple values directly, and reference types, which store references to objects such as String, arrays, classes, interfaces, and collections.
A primitive variable holds the actual value, while a reference variable holds a reference to an object. This difference affects default values, comparison, memory behavior, null handling, and method calls.
Java has 8 primitive data types built into the language. Everything else is a reference type. This includes String, arrays, wrapper classes, user-defined classes, enums, interfaces, and collection classes.
Primitive types are lightweight and cannot be null. Reference types can be null because the variable may point to no object.
| Category | Examples | Stores | Can be null? |
|---|---|---|---|
| Primitive | int, double, boolean, char | The actual value | No |
| Reference | String, int[], Student, ArrayList | A reference to an object | Yes |
public class TypeCategories {
public static void main(String[] args) {
int age = 25; // primitive
double salary = 45000.50; // primitive
boolean active = true; // primitive
String name = "Anil"; // reference type
int[] marks = {80, 90, 75}; // reference type
System.out.println(age);
System.out.println(salary);
System.out.println(active);
System.out.println(name);
System.out.println(marks[0]);
}
}
Primitive types are used for numbers, characters, and true/false values. Choose the type based on the size and meaning of the data, not only because it "works".
| Type | Size | Default for fields | Common Use | Range or Values |
|---|---|---|---|---|
| byte | 1 byte | 0 | Small numbers, binary data | -128 to 127 |
| short | 2 bytes | 0 | Rarely used; small integer ranges | -32,768 to 32,767 |
| int | 4 bytes | 0 | Default integer type for most whole numbers | -2,147,483,648 to 2,147,483,647 |
| long | 8 bytes | 0L | Large whole numbers, IDs, timestamps | About -9.22e18 to 9.22e18 |
| float | 4 bytes | 0.0f | Single-precision decimal numbers | About 6 to 7 decimal digits |
| double | 8 bytes | 0.0d | Default decimal type for most calculations | About 15 decimal digits |
| char | 2 bytes | \u0000 | One UTF-16 code unit | 0 to 65,535 |
| boolean | JVM-dependent | false | Conditions and flags | true or false |
public class PrimitiveTypes {
public static void main(String[] args) {
byte b = 100;
short s = 30000;
int i = 2_000_000; // underscores improve readability
long l = 9_000_000_000L;
float f = 3.14f;
double d = 3.141592653589793;
char c = 'A';
boolean flag = true;
System.out.println("byte: " + b);
System.out.println("short: " + s);
System.out.println("int: " + i);
System.out.println("long: " + l);
System.out.println("float: " + f);
System.out.println("double: " + d);
System.out.println("char: " + c);
System.out.println("boolean: " + flag);
}
}
Use int for most normal whole-number values. Use long when the value can exceed the int range, such as large IDs, file sizes, or time values in milliseconds.
byte and short are useful in memory-sensitive arrays or binary processing, but local arithmetic with them often promotes values to int.
public class IntegerTypes {
public static void main(String[] args) {
int population = 1_400_000_000;
long distanceToStar = 40_208_000_000_000L;
byte level = 10;
short year = 2026;
System.out.println(population);
System.out.println(distanceToStar);
System.out.println(level);
System.out.println(year);
}
}
Use double for most decimal calculations. Use float only when you specifically need single precision, such as some graphics, game, or memory-sensitive numeric arrays.
Do not use float or double for exact money calculations. Decimal floating-point values can contain small precision errors. For money, use BigDecimal.
public class DecimalTypes {
public static void main(String[] args) {
double price = 19.99;
float rating = 4.5f;
System.out.println(price);
System.out.println(rating);
double result = 0.1 + 0.2;
System.out.println(result); // 0.30000000000000004
}
}
import java.math.BigDecimal;
public class MoneyCalculation {
public static void main(String[] args) {
BigDecimal price = new BigDecimal("19.99");
BigDecimal tax = new BigDecimal("1.50");
BigDecimal total = price.add(tax);
System.out.println(total); // 21.49
}
}
The char type stores a single UTF-16 code unit and uses single quotes. The boolean type stores only true or false and is used in conditions, loops, and flags.
public class CharBooleanDemo {
public static void main(String[] args) {
char grade = 'A';
char rupee = '\u20B9';
int gradeCode = grade; // char can widen to int
boolean passed = grade == 'A';
System.out.println(grade);
System.out.println(rupee);
System.out.println(gradeCode);
System.out.println(passed);
}
}
Fields get default values automatically, but local variables do not. A local variable must be assigned before it is used.
| Type | Default Field Value |
|---|---|
| byte | 0 |
| short | 0 |
| int | 0 |
| long | 0L |
| float | 0.0f |
| double | 0.0d |
| char | \u0000 |
| boolean | false |
| Reference types | null |
public class DefaultValues {
int count; // default 0
boolean active; // default false
String name; // default null
public static void main(String[] args) {
DefaultValues obj = new DefaultValues();
System.out.println(obj.count);
System.out.println(obj.active);
System.out.println(obj.name);
int localCount;
// System.out.println(localCount); // ERROR: variable might not have been initialized
}
}
Reference variables point to objects. String is the most common reference type beginners use. Arrays are also reference types, even when they store primitive values.
Because references can be null, calling a method on a null reference causes NullPointerException.
public class ReferenceTypes {
public static void main(String[] args) {
String name = "Java";
int[] scores = {85, 90, 78};
System.out.println(name.toUpperCase());
System.out.println(scores.length);
System.out.println(scores[0]);
String city = null;
// System.out.println(city.length()); // NullPointerException
}
}
Each primitive type has a wrapper class in java.lang. Wrapper classes let primitive values behave like objects, which is required in collections such as ArrayList<Integer>.
| Primitive | Wrapper Class | Useful Examples |
|---|---|---|
| byte | Byte | Byte.parseByte("10") |
| short | Short | Short.parseShort("100") |
| int | Integer | Integer.parseInt("500"), Integer.MAX_VALUE |
| long | Long | Long.parseLong("9000") |
| float | Float | Float.parseFloat("3.14") |
| double | Double | Double.parseDouble("3.14") |
| char | Character | Character.isDigit('5') |
| boolean | Boolean | Boolean.parseBoolean("true") |
Autoboxing converts a primitive value to its wrapper object automatically. Unboxing converts a wrapper object back to a primitive value automatically.
This is convenient, but it can hide performance cost and null-related errors.
import java.util.ArrayList;
public class AutoboxingDemo {
public static void main(String[] args) {
int primitive = 42;
Integer wrapped = primitive; // autoboxing
int back = wrapped; // unboxing
System.out.println("Wrapped: " + wrapped);
System.out.println("Back: " + back);
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(10); // int becomes Integer
int first = numbers.get(0); // Integer becomes int
System.out.println(first);
}
}
public class UnboxingProblem {
public static void main(String[] args) {
Integer count = null;
// int value = count; // NullPointerException at runtime
int safeValue = (count == null) ? 0 : count;
System.out.println(safeValue);
}
}
Type conversion means changing a value from one type to another. Java allows safe widening conversions automatically. Risky narrowing conversions require an explicit cast.
public class TypeCasting {
public static void main(String[] args) {
int i = 100;
long l = i; // implicit widening
double d = l; // implicit widening
System.out.println("Widening: " + d); // 100.0
double pi = 3.99;
int truncated = (int) pi; // fractional part is dropped, NOT rounded
System.out.println("Narrowing: " + truncated); // 3
long big = 3_000_000_000L;
int overflow = (int) big;
System.out.println("Overflow: " + overflow);
char ch = 'A';
int ascii = ch; // widening: char to int
char back = (char) 66; // narrowing: int to char
System.out.println("char to int: " + ascii); // 65
System.out.println("int to char: " + back); // B
}
}
Java promotes smaller numeric types during arithmetic. byte, short, and char are usually promoted to int before calculation.
public class NumericPromotion {
public static void main(String[] args) {
byte a = 10;
byte b = 20;
int sum = a + b; // byte + byte becomes int
byte smallSum = (byte) (a + b);
int x = 5;
double y = 2.0;
double result = x / y; // result is double
System.out.println(sum);
System.out.println(smallSum);
System.out.println(result);
}
}
The var keyword lets the compiler infer the local variable type from the assigned value. It does not make Java dynamically typed. The type is still fixed at compile time.
public class VarDemo {
public static void main(String[] args) {
var name = "Java"; // inferred as String
var count = 10; // inferred as int
var price = 99.50; // inferred as double
// name = 100; // ERROR: name is still a String
// var value; // ERROR: initializer required
System.out.println(name);
System.out.println(count);
System.out.println(price);
}
}
Good type choices make programs easier to understand and safer to maintain. Choose the smallest conceptually correct type, but do not over-optimize too early.
| Need | Recommended Type | Reason |
|---|---|---|
| Age, count, marks | int | Simple and standard for whole numbers. |
| Large IDs or milliseconds | long | Avoid int range overflow. |
| Decimal calculations | double | Default decimal type. |
| Exact money values | BigDecimal | Avoid floating-point precision errors. |
| Single character | char | Stores one UTF-16 code unit. |
| Yes/no flag | boolean | Best for conditions and state. |
| Text | String | Standard text type. |
| Multiple values of same type | array | Simple fixed-size collection. |
float price = 19.99;
float price = 19.99f;
long value = 3000000000;
long value = 3000000000L;
if (count) { }
if (count > 0) { }
String a = new String("Java"); String b = new String("Java"); a == b
a.equals(b)
Integer count = null; int total = count;
int total = (count == null) ? 0 : count;
Java has 8 primitive data types: <code>byte</code>, <code>short</code>, <code>int</code>, <code>long</code>, <code>float</code>, <code>double</code>, <code>char</code>, and <code>boolean</code>.
No. <code>String</code> is a reference type and an object. It is commonly used like a basic type, but it is not primitive.
Use <code>double</code> for most decimal calculations. Use <code>float</code> only when single precision is specifically required.
Java promotes smaller integer types such as <code>byte</code>, <code>short</code>, and <code>char</code> to <code>int</code> during arithmetic expressions.
No. Primitive variables always hold a value. Wrapper classes and other reference types can be null.
<code>int</code> is a primitive type. <code>Integer</code> is a wrapper class that represents an int value as an object.
Explore 500+ free tutorials across 20+ languages and frameworks.