Topic 18 of 119 2. Fundamentals of Java Programming Interactive Tutorial

Java Data Types: Primitive Values and Reference-Based Types

16 mins read Last updated: 22 Aug 2026 18,502 views

Direct Answer & Core Concept

Java splits its data types into two families. The eight primitive types are byte, short, int, long, float, double, char and boolean. The four integer types differ only in size, so you pick the smallest one that still holds your range. The two floating-point types store decimals, with double being the default. char holds a single 16-bit Unicode character and boolean holds only true or false. Everything else is a reference type, including String, arrays, interfaces, enums, records and your own classes. Primitives store raw values directly and can never be null, while references store an address and can be null.

Detailed Explanation & Mechanics

1. What Are Data Types, and Why Do They Matter?

A data type tells Java what kind of value a variable can hold, how much memory to reserve, and which operations make sense. When you write int age = 25; the word int is the instruction that everything else depends on.

Main.java
Run Online
byte smallNumber = 25;
// small box, saves memory
long hugeNumber = 9876543210L;
double price = 1499.99;
boolean isAvailable = true;

Java is strongly typed, which means the compiler checks the type of every variable and every expression for you. Store a String in an int and the program never compiles. That strictness sounds annoying for the first few days, then it turns into the thing you rely on most.

Choosing the right type matters for three reasons.

  • Memory. An int array of a million numbers uses four million bytes, while a byte array uses one million. In large systems that difference adds up quickly.
  • Correctness. The type defines the range of values you can store, so the wrong type can silently overflow.
  • Clarity. Reading double temperature tells a colleague that decimals are expected, while reading double value says nothing.

2. The Two Families: Primitive and Reference Types

Every data type in Java belongs to one of two families, and knowing which family you are in explains most of the language's behaviour.

Main.java
Run Online
JAVA DATA TYPES +--------------------------------------+ +--------------------------------+ | PRIMITIVE TYPES(8) | | REFERENCE TYPES | | | | | | byte short int long | | your own classes | | float double char boolean | | String, ArrayList, Integer | | | | arrays, interfaces, enums | | * raw value stored directly | | records, lambdas | | * fixed size | | * address of an object | | * can NEVER be null | | * CAN be null | | * no methods | | * have methods | +--------------------------------------+ +--------------------------------+

The single most practical difference is null. A primitive always holds a real value, so the compiler guarantees you will never face a missing value. A reference type can point at nothing, which is exactly what causes the NullPointerException that every Java developer meets at least once.

The second difference is size. A primitive occupies a fixed, known number of bytes. An object can be any size, because it carries a header plus whatever fields and methods it needs.

3. The 8 Primitive Data Types at a Glance

This one table is worth bookmarking. It covers every primitive you will use for years.

TypeSizeRangeDefaultStores
byte8 bits / 1 byte-128 to 1270Small whole numbers
short16 bits / 2 bytes-32,768 to 32,7670Smallish whole numbers
int32 bits / 4 bytesabout -2.1 billion to 2.1 billion0General whole numbers
long64 bits / 8 bytesabout -9.2 quintillion to 9.2 quintillion0LVery large whole numbers
float32 bits / 4 bytesabout 3.4 x 10 to the power 380.0fApproximate decimals
double64 bits / 8 bytesabout 1.79 x 10 to the power 3080.0dDecimals, the default
char16 bits / 2 bytes0 to 65,535the null characterOne Unicode character
booleannot fixed by the spectrue or falsefalseYes or no answers

Two details catch people out. First, char is unsigned in Java, so it never goes negative. Second, the specification does not fix the size of boolean, so do not build anything that depends on it being exactly one byte.

4. The Four Integer Types

byte, short, int and long all hold whole numbers with no decimal part. They differ only in size, which means the same value can be held by any of them.

Main.java
Run Online
public class IntegerTypes {
    public static void main(String[] args) {
        byte sensorReading = 120;
        // fits comfortably
        short temperature = -450;
        // also fine
        int itemCount = 250_000;
        // underscores are allowed
        long transactionId = 9_876_543_210L;
        System.out.println(sensorReading + " " + temperature);
        System.out.println(itemCount + " " + transactionId);
        byte overflow =(byte) 130;
        // wraps around to -126
        System.out.println("byte holding 130 becomes " + overflow);
    }
}
  • int is the default type for a whole-number literal, so long values need an L suffix.
  • Overflow wraps around rather than throwing, which is why large calculation bugs are so hard to spot.
  • Java 7 and later allow underscores in numeric literals for readability, as in 250_000.

5. Floating-Point Types: float and double

The two floating-point types store numbers with a decimal point. They differ mainly in how many significant digits they can keep accurately.

Propertyfloatdouble
Size32 bits64 bits
Accurate digitsabout 6 to 9about 15 to 17
Suffixf or Fd or D (optional)
Default for decimalsNoYes
Good forMemory savings, rough mathsScientific, engineering, everyday use

Because decimals cannot be written exactly in binary, some values are stored as an approximation. That single fact causes an enormous number of beginner bugs.

Main.java
Run Online
public class FloatingPointDemo {
    public static void main(String[] args) {
        double sum = 0.1 + 0.2;
        // people expect 0.3
        System.out.println(sum);
        // prints 0.30000000000000004
        float a = 0.1f;
        double b = a;
        // 0.10000000149011612
        double regular = 3.14;
        // this is a double, not a float
        float forced = 3.14f;
        // the f suffix forces a float
        System.out.println("regular=" + regular + ", forced=" + forced);
    }
}
  • Never use float or double for money. Use java.math.BigDecimal, which stores decimal values exactly.
  • Write an L or l suffix on large whole numbers, and an f suffix when you specifically want a float.
  • A scientific literal such as 1.5e10 is a double unless you add the f suffix.

6. The char Type: A Single Unicode Character

A char holds exactly one character and is written with single quotes. It uses 16-bit UTF-16 encoding, which is why it can represent far more than the English alphabet.

Main.java
Run Online
public class CharDemo {
    public static void main(String[] args) {
        char grade = 'A';
        char rupee = '₹';
        char smiley = '☕';
        System.out.println(grade + " " + rupee + " " + smiley);
        System.out.println("grade as a number = " +(int) grade);
        // 65
        char next;
        next =(char)(grade + 1);
        // cast is required
        System.out.println("next grade = " + next);
        // B
        // System.out.println(grade + 1);   // ERROR: char and int do not mix
    }
}
  • char uses single quotes, String uses double quotes. char c = 'a'; and String s = "a"; are different things.
  • Java will not do arithmetic with char directly. Cast to int first, then convert back.
  • char is unsigned, so its range is 0 to 65,535 and it never goes negative.

7. The boolean Type

The boolean type has only two possible values: true and false. It is the type behind every if statement and every yes-or-no answer in your program.

Main.java
Run Online
public class BooleanDemo {
    public static void main(String[] args) {
        boolean isJavaFun = true;
        boolean hasError = false;
        if (isJavaFun && !hasError) {
            System.out.println("Ready to build");
        } // int total = true;        // ERROR: boolean cannot be used as a number
        // System.out.println(true + 1);   // ERROR for the same reason
    }
}
  • In many older languages like C, a boolean is really a number. Java is strict here: it will not compile.
  • Use boolean rather than int flags such as isActiveFlag = 1, because the name itself documents the meaning.

8. Reference Types: What Counts and What Does Not

Anything that is not one of the eight primitives is a reference type. That list is longer than most beginners expect, and it contains two famous surprises.

  • Your own classes are reference types, obviously.
  • Arrays are reference types, so int[] can be null even though the int elements can never be null.
  • String is a reference type, not a primitive. This surprises anyone arriving from C.
  • Interfaces, enums, records and even lambdas are all reference types.
Main.java
Run Online
public class ReferenceTypesDemo {
    public static void main(String[] args) {
        String[] names = new String[] {
            "Asha", "Bilal", "Chandra"
        };
        int[] numbers = new int[3];
        // array is null-able, elements are not
        numbers[0] = 10;
        String missingName = null;
        // legal, because String is a reference
        // int missingNumber = null;       // ERROR, int is a primitive
        for (String name : names) {
            System.out.println(name);
        } System.out.println("missingName is null? " +(missingName == null));
        System.out.println("numbers[1] default = " + numbers[1]);
        // 0
    }
}

An array is the interesting case, because the container and the contents follow different rules. The array reference can be null, every reference element inside it can be null, and yet the primitive elements are quietly filled with their default values.

9. Wrapper Classes and Autoboxing

Java cannot put a primitive directly inside a generic class such as ArrayList, because generics only accept objects. For each primitive, Java provides a wrapper class.

PrimitiveWrapper ClassPrimitiveWrapper Class
byteBytefloatFloat
shortShortdoubleDouble
intIntegercharCharacter
longLongbooleanBoolean

Java 5 introduced autoboxing, which converts between a primitive and its wrapper automatically, so you rarely write the conversions by hand.

Main.java
Run Online
import java.util.ArrayList;
import java.util.List;
public class AutoboxingDemo {
    public static void main(String[] args) {
        List numbers = new ArrayList();
        numbers.add(10);
        // int is boxed to Integer
        int total = 0;
        for (Integer value : numbers) {
            total += value;
            // unboxed automatically
        } Integer safe = 127;
        Integer other = 127;
        System.out.println("value " + safe + " equals " + other + "? " + safe.equals(other));
        System.out.println("total = " + total);
        System.out.println("int max = " + Integer.MAX_VALUE);
        System.out.println("parsed  = " + Integer.parseInt("500"));
    }
}
  • Use equals rather than == on wrappers, because == compares references.
  • Small values from -128 to 127 are cached, so those boxes may share one object.
  • Wrapper classes give you the exact range of each primitive, as in Long.MIN_VALUE.

10. Default Values of Every Type

Fields and array elements receive a default value automatically. Local variables receive nothing at all, which is exactly why the compiler insists you assign them yourself.

Type GroupDefault ValueLocal Variable Default
byte, short, int, long0None, must be assigned
float0.0fNone, must be assigned
double0.0dNone, must be assigned
charthe null characterNone, must be assigned
booleanfalseNone, must be assigned
String, arrays, objectsnullNone, must be assigned
Main.java
Run Online
public class DefaultValues {
    int number;
    double price;
    char grade;
    String title;
    public static void main(String[] args) {
        DefaultValues d = new DefaultValues();
        System.out.println("number=" + d.number + " price=" + d.price);
        System.out.println("gradeCode=" +(int) d.grade + " title=" + d.title);
        int[] scores = new int[3];
        // every element gets 0
        System.out.println(scores[0] + " " + scores[1] + " " + scores[2]);
        int local;
        // ERROR if you print it unassigned
        // System.out.println(local);
        local = 7;
        System.out.println("local=" + local);
    }
}

11. Type Conversion: Widening and Narrowing

Java converts between numeric types automatically in one direction, and only with your permission in the other.

Architecture Diagram
WIDENING IS AUTOMATIC AND ALWAYS SAFE

   byte ---> short ---> int ---> long ---> float ---> double
                    ^
                    |
            char ---+          char also widens into int

NARROWING NEEDS AN EXPLICIT CAST AND CAN LOSE DATA

   double ---> float ---> long ---> int ---> short ---> byte
Main.java
Run Online
public class TypeConversionDemo {
    public static void main(String[] args) {
        byte small = 100;
        int widened = small;
        // automatic, no data lost
        long wider = small;
        // automatic again
        double widest = small;
        // automatic, still correct
        System.out.println(widened + " " + wider + " " + widest);
        int big = 300;
        byte narrow =(byte) big;
        // explicit cast, wraps to 44
        System.out.println("300 as byte = " + narrow);
        double decimal = 9.99;
        int truncated =(int) decimal;
        // cast truncates, does not round
        System.out.println("9.99 as int = " + truncated);
        // System.out.println(decimal);     // ERROR: double cannot go into int
    }
}
  • Widening never loses information, so the compiler allows it silently.
  • Narrowing may lose data, so Java makes you write the cast to prove you meant it.
  • A cast to int truncates rather than rounding, so 9.99 becomes 9.

12. Common Data Type Mistakes Beginners Make

Almost every beginner hits one of these at least once, and most of them produce a confusing error message.

What You WroteProblemCorrect Version
long id = 9876543210;Value is too big for an int literallong id = 9876543210L;
int n = 10 / 3;Integer division truncates the answerdouble n = 10 / 3.0;
char c = "A";Double quotes make a Stringchar c = 'A';
char c = 'A'; c = c + 1;char and int do not mixc = (char) (c + 1);
int total = 0.1 + 0.2;Result is not exactly 0.3Use BigDecimal for money
Integer a = 127; Integer b = 127; a == bCompares referencesUse a.equals(b)
double price = 499.99; price = 999;int cannot be assigned to doubleprice = 999; or price = 999.0;
  • The most expensive mistake in the list is the float or double money bug, because it looks correct right up until an accountant finds it.
  • Use Integer.parseInt to turn text into a number, and String.valueOf to turn a number into text.
  • Never write a decimal without thinking about the type. It defaults to double, which is usually what you want.

13. Choosing the Right Data Type

A simple decision guide saves a lot of second-guessing later.

Main.java
Run Online
WHAT ARE YOU STORING? | +-- a whole number that can be negative? | +-- small, -128 to 127 .............. byte | +-- fits in -32,768 to 32,767 ....... short | +-- almost certainly yes ........... int
  • Default to int and double. Move to long or BigDecimal only when a real requirement appears.
  • Use final where the value should never change, so the compiler helps you keep the promise.
  • Prefer a specific type such as String or LocalDate over Object in application code.

14. Java Data Types Cheat Sheet

The whole topic compressed into one screen.

QuestionAnswer
How many primitives?8: byte, short, int, long, float, double, char, boolean
Default integer type?int, with a range of about 2.1 billion either way
Default decimal type?double
Can a primitive be null?No, only reference types can
Is String primitive?No, it is a reference type
Is an array primitive?No, the array is a reference even though its elements may not be
Can you do char plus int?No, cast to int first
Type for money?BigDecimal, never float or double
Widening conversion?Automatic and lossless, smaller type to larger
Narrowing conversion?Needs an explicit cast and can overflow
Wrapper classes for?Generics, collections and helper methods such as Integer.MAX_VALUE

With the type system clear in your head, the next topic, Java literals, becomes obvious, because a literal is simply the literal value you write at a particular type.

Runnable Code Example: Java Data Types

Java 17+
Main.java
Run Online
public class DataTypesDemo {
    // Primitive fields always start from the default values
    byte byteField;
    short shortField;
    int intField;
    long longField;
    float floatField;
    double doubleField;
    char charField;
    boolean booleanField;
    public static void main(String[] args) {
        DataTypesDemo demo = new DataTypesDemo();
        // Default values of a primitive field
        System.out.println("defaults -> byte=" + demo.byteField + " charCode=" +(int) demo.charField + " boolean=" + demo.booleanField + " double=" + demo.doubleField);
        // Declaring all eight primitives
        byte age = 25;
        short yearOfBirth = 2000;
        int phoneCount = 1200;
        long phone = 9876543210L;
        float ratio = 0.75f;
        double price = 1499.99;
        char grade = 'A';
        boolean isActive = true;
        System.out.println("byte=" + age + ", short=" + yearOfBirth + ", int=" + phoneCount);
        System.out.println("long=" + phone + ", float=" + ratio + ", double=" + price + ", char=" + grade + ", boolean=" + isActive);
        // char and boolean are NOT numeric in Java
        System.out.println("char as code = " +(int) grade);
        // 65
        // System.out.println(grade + 1);                     // ERROR: char + int
        // Widening happens automatically (byte -> int)
        byte small = 100;
        int widened = small;
        // no cast needed
        System.out.println("widened = " + widened);
        // Narrowing needs an explicit cast and can lose data
        int big = 300;
        byte narrow =(byte) big;
        // overflow wraps to 44
        System.out.println("narrowed = " + narrow);
        // Autoboxing turns a primitive into its wrapper object
        Integer boxed = price;
        // double -> Double, autoboxed
        System.out.println("boxed = " + boxed + ", is null? " +(boxed == null));
        // String is a reference type, never a primitive
        String name = "Java";
        String missing = null;
        System.out.println("name.length() = " + name.length() + ", missing is null? " +(missing == null));
        // Limits of each type are available from the wrapper classes
        System.out.println("byte  range = " + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE);
        System.out.println("int   range = " + Integer.MIN_VALUE + " to " + Integer.MAX_VALUE);
        System.out.println("long  range = " + Long.MIN_VALUE + " to " + Long.MAX_VALUE);
    }
}

Common Java Technical Interview Questions & Answers

Interview Prep
Q1

How many primitive data types does Java have and what are they?

Eight. They are byte, short, int and long for integers, float and double for decimals, char for a single character, and boolean for true or false.
Q2

Why is char two bytes in Java when it is one byte in C?

Java uses 16-bit UTF-16 encoding for char so it can represent any Unicode code unit, which covers far more than the 256 values of an 8-bit byte. A plain char can therefore hold values from 0 to 65,535.
Q3

Which data type should I use for a whole number by default?

int. It handles values from about minus 2.1 billion to 2.1 billion and is the default for integer literals. Move up to long only when the value genuinely does not fit, and down to byte or short for small values to save memory in large arrays.
Q4

What is the difference between float and double?

float uses 32 bits and gives roughly 6 to 9 significant decimal digits, while double uses 64 bits and gives roughly 15 to 17. double is the default for decimal literals, so 3.14 is a double, and you need an f suffix to force a float.
Q5

Why should I avoid float and double for money?

Both store values in binary, so numbers such as 0.1 cannot be represented exactly and rounding errors appear. For financial work use java.math.BigDecimal, which stores decimal values exactly.
Q6

Can a primitive variable ever hold null?

No. Primitives always hold a concrete value, and a default such as 0 or false is written in for them. Only reference types can be null, which is why a String may start as null while an int cannot.
Q7

Is String a primitive type in Java?

No, and this surprises people coming from C. String is a reference type, so it can be null, it has methods such as length and substring, and two Strings with identical content are equal in content even when they are different objects.
Q8

What is autoboxing?

It is the automatic conversion between a primitive and its matching wrapper class, added in Java 5. Writing Integer count = 5 boxes the int into an Integer, and reading it back unboxes automatically.
Q9

What are wrapper classes and why do they exist?

Byte, Short, Integer, Long, Float, Double, Character and Boolean wrap a primitive inside an object. They are needed because generics and collections such as ArrayList cannot hold primitives, and they provide constants such as Integer.MAX_VALUE and helper methods such as Integer.parseInt.
Q10

Is an int array a primitive type?

No. An array is always a reference type, so int[] can be null. The elements inside it are primitives, which means int[] is cheaper in memory than Integer[], where every element is a separate object.
Q11

What happens when I convert between numeric types?

Converting a smaller type to a larger one is widening, happens automatically and never loses data. Converting a larger type to a smaller one is narrowing, needs an explicit cast, and can silently overflow, so 300 cast to a byte becomes 44.
Q12

Can I do arithmetic with a char in Java?

Not directly. Unlike C, Java will not let you write grade + 1, because char is not treated as a number. Cast it first, such as (char) (grade + 1) or (int) grade, and the arithmetic works normally.

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Pick the smallest type that safely holds your range, and start from int and double because they cover most everyday code. Use long for timestamps, identifiers and anything that can exceed two billion. Prefer double over float unless memory is genuinely tight, since the extra precision costs you almost nothing. Never use float or double for money, rupees or anything that must add up exactly, because use BigDecimal for those. Make a habit of treating char and boolean as non-numeric, because Java will stop you if you forget. Where you can, use final or better still an immutable type, so the compiler protects the value for you. Finally, choose reference types only when you need the extra behaviour they bring, because every object adds memory overhead and a chance of a null reference.
We value your privacy & transparency

OperateTools uses cookies and local storage to ensure basic tool functionality, preserve preferences, and analyze aggregated traffic. We never sell your personal data or index your document files. Learn more in our Privacy Policy.