Wrapper classes

A form gives you "250" as text, a list refuses to hold an int, and a database says a mark is missing. Java's wrapper classes (Integer, Double, Character, Boolean and four more) turn primitive values into objects so they can do all of this. You'll learn the eight wrappers, how to convert between text, primitives and objects, and the cache that makes == lie.

Module 10 · Core Classes⏱ 20 minIntermediate8 practice problems
1 The story

A list that won't take a number

Riya is building a marks tracker for her class. She wants a growing list of marks, she reads each mark from a text box, and some students haven't taken the test yet. Three problems hit her in ten minutes.

ArrayList<int> marks ✗ unexpected type required: reference ArrayList<Integer> marks ✓ holds Integer objects 85 int: a bare value Integer object 85 a value wrapped in an object "85"from a form parseInt("85")→ 85 Integer m = null;“not taken yet” myphatshala.in
Riya

Sir, ArrayList<int> won't compile, the text box gives me "85" instead of 85, and I have no way to say “this student has no mark yet”. 0 would be a real mark!

Arjun Sir

All three have the same answer: wrapper classes. Collections can only hold objects, so Java gives every primitive an object version. int has Integer. Use ArrayList<Integer>.

Riya

And the text?

Arjun Sir

Integer.parseInt("85") reads text and gives you the number. And because an Integer is an object, a variable of that type can hold null, which means “no value”. An int can never be null.

Riya

So wrappers are just boxes around numbers?

Arjun Sir

Boxes with a toolkit: converting, comparing, limits like Integer.MAX_VALUE. And one trap with == that catches many freshers. Let's open the box.

2 Definition

What are wrapper classes?

Formal definition (write this in exams)

A wrapper class is a class in java.lang whose objects hold a single value of a primitive type. Java has eight: Byte, Short, Integer, Long, Float, Double, Character and Boolean. They let primitive values be used where objects are required (collections, generics, null), and provide constants and static utility methods for conversion and comparison. Wrapper classes are final and their objects are immutable.

In simple words

A primitive is a bare value. A wrapper puts that value inside an object, so it can go wherever Java expects an object, and gives you handy tools to work with it.

Words you'll meet in this lesson

PrimitiveOne of the 8 basic value types: byte short int long float double char boolean (Lesson 2.2).
BoxingPutting a primitive value into a wrapper object: Integer.valueOf(85).
UnboxingTaking the primitive back out: m.intValue().
ParsingReading text and turning it into a number: Integer.parseInt("85").
ImmutableCan't be changed after creation. An Integer holding 85 holds 85 forever.
CacheReady-made objects Java reuses. Integer.valueOf reuses objects for -128 to 127.

The eight wrappers

PrimitiveWrapper classSizeExample
byteByte8 bitsByte.MAX_VALUE → 127
shortShort16 bitsShort.parseShort("300")
intInteger32 bitsInteger.parseInt("85")
longLong64 bitsLong.parseLong("9876543210")
floatFloat32 bitsFloat.parseFloat("2.5")
doubleDouble64 bitsDouble.parseDouble("99.5")
charCharacter16 bitsCharacter.isDigit('7')
booleanBoolean(JVM-dependent)Boolean.parseBoolean("true")
Packagejava.lang: available without any import
Numeric parentThe six number wrappers extend the abstract class Number (intValue(), doubleValue() …)
Mutable?No. Every wrapper object is immutable, like String
Can be null?Yes, a wrapper variable can hold null; a primitive can't
Constructorsnew Integer(5) is deprecated and marked for removal; use Integer.valueOf(5)

Exam tip: only two wrapper names differ from their primitive: int → Integer and char → Character. The rest just capitalise the first letter. And remember: wrapper classes are final (no subclasses) and immutable.

3 Types and ways to use it

Five jobs a wrapper class does

1. Create an object

Integer.valueOf(85), or just Integer m = 85; (autoboxing, next lesson).

boxing

2. Text to number

parseInt gives a primitive; valueOf(String) gives a wrapper object.

parsing input

3. Limits and constants

Integer.MAX_VALUE, Long.MIN_VALUE, Integer.BYTES.

constants

4. Check characters

Character.isDigit, isLetter, isUpperCase, toUpperCase.

validation

5. Compare and convert

Integer.compare, equals, toBinaryString, toString.

utilities

Text to number: parseXxx vs valueOf

public class Main {
    public static void main(String[] args) {
        String fromForm = "250";

        int qty = Integer.parseInt(fromForm);        // primitive int
        Integer boxed = Integer.valueOf(fromForm);   // Integer object
        double price = Double.parseDouble("99.5");
        boolean agreed = Boolean.parseBoolean("TRUE"); // case-insensitive

        System.out.println(qty + 1);
        System.out.println(boxed);
        System.out.println(price * 2);
        System.out.println(agreed);
    }
}
251 250 199.0 true

If the text is not a valid number, parsing throws NumberFormatException, an unchecked exception (Lesson 9.3):

public class Main {
    public static void main(String[] args) {
        String[] inputs = {"42", "12a", ""};
        for (String s : inputs) {
            try {
                System.out.println("ok: " + Integer.parseInt(s));
            } catch (NumberFormatException e) {
                System.out.println("bad: " + e.getMessage());
            }
        }
    }
}
ok: 42 bad: For input string: "12a" bad: For input string: ""

Limits, characters and handy utilities

public class Main {
    public static void main(String[] args) {
        System.out.println(Integer.MAX_VALUE);           // biggest int
        System.out.println(Integer.MIN_VALUE);
        System.out.println(Byte.MAX_VALUE);

        System.out.println(Character.isDigit('7'));       // true
        System.out.println(Character.isLetter('#'));      // false
        System.out.println(Character.toUpperCase('r'));   // R

        System.out.println(Integer.toBinaryString(10));   // 1010
        System.out.println(Integer.toHexString(255));     // ff
        System.out.println(Integer.compare(5, 9));        // negative: 5 < 9
    }
}
2147483647 -2147483648 127 true false R 1010 ff -1

Comparing wrappers: equals, not ==

public class Main {
    public static void main(String[] args) {
        Integer a = Integer.valueOf(127), b = Integer.valueOf(127);
        Integer c = Integer.valueOf(128), d = Integer.valueOf(128);

        System.out.println(a == b);        // same cached object
        System.out.println(c == d);        // two different objects!
        System.out.println(c.equals(d));   // compares the values
    }
}
true false true

The Integer cache trap: Integer.valueOf keeps ready-made objects for -128 to 127 and hands out the same one every time. Outside that range it creates a new object. == compares references (is it the same object?), so it says true for 127 and false for 128. Always compare wrapper values with equals(), or unbox to int first.

Which one to pick? Use primitives (int, double) for calculations and loop counters: they're faster and can't be null. Use wrappers when you need an object: in collections and generics, when “no value” (null) is meaningful, or for the static helper methods.

4 Step by step

What happens when you call Integer.valueOf

  1. You ask for an Integer

    Integer seats = Integer.valueOf(120);
    valueOf is a static factory method of class Integer. It decides whether to reuse an object or create one.
  2. Is the value between -128 and 127?

    The JDK has an inner class Integer.IntegerCache holding an array of 256 ready-made Integer objects, created when the cache class is first initialised. For 120, valueOf returns the object at that slot. No new object is created.
  3. Outside the range: a new object

    Integer fare = Integer.valueOf(500);   // new Integer object on the heap
    For 500, valueOf creates a fresh object on the heap. Ask again for 500 and you get another fresh object. That's why == is unreliable.
  4. The variable holds a reference

    seats is a reference on the stack (like any object variable, Lesson 2.3). The value 120 lives inside the object on the heap, in a private final int value field.
  5. Getting the number back

    int n = fare.intValue();   // unboxing: copies 500 out of the object
    intValue() reads the private value field and returns a plain int. The object is unchanged: wrappers are immutable, so “changing” a wrapper variable always means pointing it to a different object.
5 See it happen

Cached and new Integer objects: both views

Left: the code and what it prints. Right: the stack and heap, with the JDK's cache of ready-made Integer objects.

Integer.valueOf: cached or new? 6 steps
What you see int price = 120; Integer a = Integer.valueOf(120); Integer b = Integer.valueOf(120); Integer c = Integer.valueOf(500); Integer d = Integer.valueOf(500); print(a==b, c==d, c.equals(d)) Console true false true A plain int: just the value 120. Ask Integer for an object holding 120. Ask again for 120. Now ask for 500. Ask again for 500. == says false for 500, equals says true. myphatshala.in
Behind the screen Stack (main) Heap price 120 a → b → c → d → IntegerCache: -128 … 127 -128 … 119 120 121 … 127 Integer 500new #1 Integer 500new #2 a == b: same object ✓ c == d: two objects ✗ price holds 120 directly in main's frame. 120 is in the cache: no new object. Same cached object again: a and b match. 500 is outside the cache: a new object. Another new object for 500. == compares arrows; equals() compares values. myphatshala.in
6 Real-world use

Wrapper classes in real systems

Almost every program that reads input, stores data in collections or talks to a database uses wrapper classes, often without you noticing.

Watch it with an example: a train booking form

A booking page sends everything as text. Watch the server turn the passenger count into a number, and refuse text that isn't one.

Parsing the passenger count 5 steps
Animated example Book ticket Passengers: "2" "two" Submit Server Integer.parseInt(text) → int 2 fare = 2 × 450 NumberFormatException For input string: "two" Fare: ₹900 for 2 passengers Please enter the number of passengers in digits myphatshala.in
"2"int 2

1. Reading form and API input

Web forms, command-line arguments, query strings and JSON fields often arrive as text. Booking sites parse “number of passengers”, shops parse quantities, and every parse is wrapped in a check for bad input.

Text "2"→Integer.parseInt→int 2, or a friendly error
…

2. Collections of numbers

List<Integer> of order quantities, Map<String, Double> of product prices, Set<Long> of customer IDs. Collections and generics only work with objects (Module 11).

Values→Integer / Double objects→ArrayList, HashMap
marks: 85marks: NULL

3. “No value” from databases

A SQL column can be NULL (not entered). Data-access code maps it to an Integer or Double field that can be null. An int field would silently turn it into 0, a real but wrong value.

DB column NULL→Integer marks = null→shown as “Absent”
SBIN0001234✓ isDigit / isLetter

4. Validating codes and passwords

IFSC codes, PIN codes, vehicle numbers and password rules are checked character by character with Character.isDigit, isLetter and isUpperCase.

Each char→Character.isDigit(c)→valid / invalid
timeout=30

5. Configuration values

Settings files store everything as text: timeout=30, debug=true. Applications read them with Integer.parseInt and Boolean.parseBoolean at start-up.

config text→parseInt / parseBoolean→typed settings

Examples are simplified. Real systems add more checks, such as ranges, trimming spaces and logging rejected input.

7 Run the code

A billing counter that reads text input safely

import java.util.ArrayList;

public class Main {
    static Integer readQty(String text) {
        try {
            return Integer.valueOf(text.trim());
        } catch (NumberFormatException e) {
            return null;                       // null means "invalid"
        }
    }

    public static void main(String[] args) {
        String[] typed = {"2", " 5 ", "two", "1"};
        ArrayList<Integer> qtys = new ArrayList<>();

        for (String t : typed) {
            Integer q = readQty(t);
            if (q == null) {
                System.out.println("Skipped: '" + t + "'");
            } else {
                qtys.add(q);
            }
        }
        int total = 0;
        for (Integer q : qtys) {
            total += q.intValue();
        }
        System.out.println("Quantities: " + qtys);
        System.out.println("Total items: " + total);
    }
}
Skipped: 'two' Quantities: [2, 5, 1] Total items: 8
  • Integer.valueOf(text.trim())Removes spaces, then parses the text into an Integer object.
  • return null;Only possible because the return type is Integer, not int. Null signals “bad input”.
  • ArrayList<Integer>A list must hold objects, so we store Integer, not int.
  • q.intValue()Unboxes the object to a plain int for the arithmetic.
8 Line by line

Watch the cache on the heap

This trace is recorded from the real JVM. Watch which valueOf calls create a new object (a new # number on the heap) and which hand back one that already exists.

Worked examples: real problems, solved and traced in memory

Three everyday tasks where wrapper classes do the heavy lifting: reading text, validating characters, and using null for “missing”.

Example 1Education · CSV

Average marks from a CSV line

Problem statement

A results file stores each student as one line of text: Riya,85,92,78. Write a helper that reads the marks from the line and returns the average.

Input
"Riya,85,92,78"
Expected output
Riya: 85.0

Approach

  1. Split the line on commas: the first part is the name, the rest are marks as text.
  2. A helper average(String[] parts) parses each mark with Integer.parseInt and adds it up.
  3. Divide by the count as a double and print.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 2Logistics · validation

Is this a valid PIN code?

Problem statement

A delivery app accepts Indian PIN codes. A valid PIN has exactly 6 characters, all digits, and must not start with 0. Write isValidPin(String pin).

Input
"410210", "41021A", "012345"
Expected output
true
false
false

Approach

  1. Check the length first.
  2. Reject a leading '0'.
  3. Loop over the characters and use Character.isDigit on each.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 3HR · attendance

Overtime hours with “not entered” days

Problem statement

An attendance system stores overtime hours for each day as Integer. A null means the manager hasn't entered that day yet. Total the entered hours and count the missing days.

Input
{2, null, 3, null, 1}
Expected output
Total overtime: 6 h
Days not entered: 2

Approach

  1. Store the week in an Integer[] so a day can be null.
  2. Loop: if the value is null, count it as missing; otherwise unbox and add.
  3. Print the total and the number of missing days.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

9 Quiz and revision

Check yourself

Quick revision

Lesson 10.1 in one screen

  • 8 wrappers in java.lang: Byte, Short, Integer, Long, Float, Double, Character, Boolean.
  • Why: collections and generics need objects; wrappers can be null; they carry utility methods and constants.
  • parseInt("85") → int; valueOf("85") → Integer. Bad text → NumberFormatException.
  • Constants: Integer.MAX_VALUE = 2147483647, MIN_VALUE = -2147483648.
  • Character.isDigit / isLetter / isUpperCase / toUpperCase for validation.
  • Integer cache: valueOf reuses objects for -128..127. Compare values with equals(), never ==.
  • Wrappers are final and immutable. new Integer(5) is deprecated; use valueOf.

Interview and viva questions

Why does Java need wrapper classes if it has primitives?

Primitives are fast but aren't objects. Many APIs need objects: collections, generics, methods that take Object, and anything where “no value” (null) must be represented. Wrappers bridge the two worlds and also provide parsing, conversion and comparison helpers.

What is the difference between parseInt() and valueOf()?

Integer.parseInt(String) returns a primitive int. Integer.valueOf(String) (or valueOf(int)) returns an Integer object, using the cache for -128 to 127. Both throw NumberFormatException for invalid text.

Explain the Integer cache.

Integer.valueOf returns pre-created objects for values from -128 to 127 (the upper limit can be raised with the JVM option -XX:AutoBoxCacheMax). Small numbers are very common, so reusing them saves memory. Side effect: == between two Integers is true for 127 but false for 128. Short, Long, Byte and Character (0 to 127) cache too; Float and Double do not.

Are wrapper classes mutable?

No. Each wrapper object holds its value in a private final field. count = count + 1 on an Integer variable creates (or fetches) a different object and points the variable at it.

Why is new Integer(5) deprecated?

A constructor always creates a new object, so it bypasses the cache and wastes memory. Since Java 9 the constructors are deprecated, and since Java 16 marked for removal. Integer.valueOf(5) (or autoboxing) is the recommended way.

Practice problems

Parse text safely, use the wrapper helpers, and avoid the == trap. The last three are business tasks.

P1Easy

Sum two numbers typed as text

Two text boxes contain "45" and "55". Print their sum as a number, not 4555.

Input
"45", "55"
Expected output
4555
100
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String a = "45", b = "55";
        System.out.println(a + b);
        int sum = Integer.parseInt(a) + Integer.parseInt(b);
        System.out.println(sum);
    }
}
4555 100

How it works: a + b joins two Strings. Integer.parseInt turns each into an int first, so + adds them.

P2Easy

Print the limits of int and long

Print the largest and smallest values of int and long using wrapper constants.

Input
(none)
Expected output
int:  -2147483648 to 2147483647
long: -9223372036854775808 to 9223372036854775807
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        System.out.println("int:  " + Integer.MIN_VALUE + " to " + Integer.MAX_VALUE);
        System.out.println("long: " + Long.MIN_VALUE + " to " + Long.MAX_VALUE);
    }
}
int: -2147483648 to 2147483647 long: -9223372036854775808 to 9223372036854775807

How it works: each numeric wrapper has MIN_VALUE and MAX_VALUE constants. Use them instead of typing the numbers.

P3Easy

Count digits in a mobile number

Count how many characters in "+91 98765-43210" are digits.

Input
"+91 98765-43210"
Expected output
Digits: 12
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String phone = "+91 98765-43210";
        int digits = 0;
        for (char c : phone.toCharArray()) {
            if (Character.isDigit(c)) {
                digits++;
            }
        }
        System.out.println("Digits: " + digits);
    }
}
Digits: 12

How it works: Character.isDigit returns true for 0–9. The +, space and dash are skipped.

P4Medium

Fix the == comparison

This check prints false even though both scores are 250. Fix it so it prints true, and explain why it failed.

Input
Integer s1 = 250, s2 = 250
Expected output
with == : false
equals  : true
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        Integer s1 = Integer.valueOf(250);
        Integer s2 = Integer.valueOf(250);
        System.out.println("with == : " + (s1 == s2));
        System.out.println("equals  : " + s1.equals(s2));
    }
}
with == : false equals : true

How it works: 250 is outside the Integer cache (-128..127), so two objects exist. == compares references; equals compares the values.

P5Medium

Binary, octal and hex of a number

Print 45 in binary, octal and hexadecimal, then read "2d" back from hex.

Input
45
Expected output
101101
55
2d
45
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        int n = 45;
        System.out.println(Integer.toBinaryString(n));
        System.out.println(Integer.toOctalString(n));
        System.out.println(Integer.toHexString(n));
        System.out.println(Integer.parseInt("2d", 16));
    }
}
101101 55 2d 45

How it works: the toXxxString methods convert to text in another base; parseInt(text, radix) reads text in that base.

P6Business problem

Total cart value from text prices

A shopping cart receives prices as text: "499.00", "1299.50", "bad", "75". Add the valid ones and report how many were rejected.

Input
{"499.00", "1299.50", "bad", "75"}
Expected output
Total: 1873.5
Rejected: 1
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String[] prices = {"499.00", "1299.50", "bad", "75"};
        double total = 0;
        int rejected = 0;
        for (String p : prices) {
            try {
                total += Double.parseDouble(p);
            } catch (NumberFormatException e) {
                rejected++;
            }
        }
        System.out.println("Total: " + total);
        System.out.println("Rejected: " + rejected);
    }
}
Total: 1873.5 Rejected: 1

How it works: Double.parseDouble reads decimal text. Bad entries throw NumberFormatException, which we count instead of crashing. (For real money, use paise as long or BigDecimal.)

P7Business problem

Strong password check

A password is strong if it has at least 8 characters, at least one upper-case letter, one digit and one symbol (not a letter or digit). Check "Riya@2026" and "riya2026".

Input
"Riya@2026", "riya2026"
Expected output
Riya@2026 -> true
riya2026  -> false
Show solution and explanation
public class Main {
    static boolean strong(String pw) {
        boolean upper = false, digit = false, symbol = false;
        for (char c : pw.toCharArray()) {
            if (Character.isUpperCase(c)) upper = true;
            else if (Character.isDigit(c)) digit = true;
            else if (!Character.isLetter(c)) symbol = true;
        }
        return pw.length() >= 8 && upper && digit && symbol;
    }

    public static void main(String[] args) {
        System.out.println("Riya@2026 -> " + strong("Riya@2026"));
        System.out.println("riya2026  -> " + strong("riya2026"));
    }
}
Riya@2026 -> true riya2026 -> false

How it works: one pass over the characters sets three flags using Character helpers. All four rules must hold.

P8Business problem

Read settings from a config file

A config has maxUsers=250, debug=true and timeout=abc. Read each into the right type; use a default of 30 if the timeout is invalid.

Input
{"maxUsers=250", "debug=true", "timeout=abc"}
Expected output
maxUsers=250, debug=true, timeout=30
Show solution and explanation
public class Main {
    static int intOr(String text, int fallback) {
        try {
            return Integer.parseInt(text);
        } catch (NumberFormatException e) {
            return fallback;
        }
    }

    public static void main(String[] args) {
        String[] lines = {"maxUsers=250", "debug=true", "timeout=abc"};
        int maxUsers = intOr(lines[0].split("=")[1], 100);
        boolean debug = Boolean.parseBoolean(lines[1].split("=")[1]);
        int timeout = intOr(lines[2].split("=")[1], 30);
        System.out.println("maxUsers=" + maxUsers + ", debug=" + debug + ", timeout=" + timeout);
    }
}
maxUsers=250, debug=true, timeout=30

How it works: each line is split at =. A helper parses with a fallback, so one bad setting doesn't stop the application from starting.

Real-world scenario questions (asked in company interviews)

Wrapper questions in interviews usually hide inside bugs: a comparison that “randomly” fails, a crash on empty input, a zero that should have been “missing”.

E-commerce · bug huntFresher

Order IDs match in testing, not in production

Code checks if (order.getUserId() == session.getUserId()), both returning Integer. It worked for all test users (IDs 1–50) but fails for real users with IDs in the thousands. Why?

The interviewer is checking: do you know about the Integer cache and reference comparison?

Show a strong answer
  • == on two Integer objects compares references, not values.
  • Values -128 to 127 come from the cache, so the same object is returned and == happens to be true. Larger IDs create separate objects, so it's false.
  • Fix: Objects.equals(a, b) (null-safe) or a.equals(b), or compare unboxed int values if neither can be null.
  • Add a test with IDs above 127, and a static-analysis rule that flags == on boxed types.

Avoid: “Java's == is buggy for big numbers.” It's working exactly as designed.

Banking · inputFresher

The transfer screen crashes

Users type amounts like 1,500 or leave the box empty, and the app shows a stack trace. The code is int amt = Integer.parseInt(box.getText());. How do you fix it?

The interviewer is checking: safe parsing and input validation.

Show a strong answer
  • parseInt throws NumberFormatException for commas, spaces and empty text.
  • Trim the text, remove allowed separators, then parse inside try/catch and show “Enter a valid amount”.
  • For money, use long paise or BigDecimal, not double, and check limits (greater than 0, below the daily limit).

Avoid: catching Exception and silently using 0. A transfer of ₹0 or a hidden error is worse than a clear message.

EdTech · data modelJunior

Absent students show 0 marks

The report card shows 0 for students who were absent, and their class average drops. The entity has private int marks;. What would you change?

The interviewer is checking: when to use a wrapper type for “no value”.

Show a strong answer
  • An int field can't represent “missing”, so a database NULL becomes 0.
  • Change it to Integer marks; null means absent. Show “AB” in the report and skip nulls when averaging.
  • Be careful when unboxing: int m = marks; on null throws NullPointerException (next lesson). Check for null first.

Avoid: using a magic value like -1 for absent. It leaks into averages and charts the moment someone forgets the rule.

Analytics · performanceJunior

A slow loop over ten million numbers

A report sums 10 million values using Long total = 0L; and total += values[i];. A teammate says changing one word makes it several times faster. Which word?

The interviewer is checking: the cost of wrapper objects in hot loops.

Show a strong answer
  • Change Long to long. Each += on a Long unboxes, adds, and boxes a new Long object, creating millions of short-lived objects for the garbage collector.
  • Use primitives for counters and sums; use wrappers only where an object is needed.
  • Prove it with a profiler or a simple timing before and after.

Avoid: “wrappers are always slow, never use them”. They're the right choice in collections and nullable fields.