Tipuri wrapper și autoboxing în Java

Fiecare primitiv are o clasă „înveliș” (Integer, Double, Character...); conversia automată între ele se numește autoboxing.

Sintaxă
Integer n = 5;           // autoboxing: int -> Integer
int m = n;               // unboxing: Integer -> int
List<Integer> note = List.of(9, 10);
int x = Integer.parseInt("42");

Ce face Tipuri wrapper și autoboxing

Fiecare tip primitiv are o clasă wrapper: byte → Byte, short → Short, int → Integer, long → Long, float → Float, double → Double, char → Character, boolean → Boolean. Ai nevoie de ele acolo unde Java cere obiecte, de exemplu în colecții: List<Integer>, nu List<int>.

Din Java 5, compilatorul face conversia automat: Integer n = 5; (autoboxing) și int m = n; (unboxing). Clasele wrapper au și metode utile: Integer.parseInt, Double.parseDouble, Integer.MAX_VALUE, Character.isDigit.

Un wrapper poate fi null, un primitiv nu. Unboxing-ul unui null aruncă NullPointerException. Wrapper-ele sunt obiecte, deci se compară cu equals, nu cu ==.

Exemple

Exemplul 1: Autoboxing în colecții

Numerele int sunt împachetate automat în Integer când intră în listă și despachetate când sunt adunate într-o variabilă int.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> note = new ArrayList<>();
        note.add(9);      // autoboxing
        note.add(10);
        note.add(7);

        int suma = 0;
        for (int nota : note) { // unboxing
            suma += nota;
        }
        System.out.println("note: " + note + ", sumă: " + suma);

        Integer maxim = Integer.MAX_VALUE;
        System.out.println("Integer.MAX_VALUE = " + maxim);
        System.out.println("parseInt(\"2026\") + 1 = " + (Integer.parseInt("2026") + 1));
        System.out.println("Double.valueOf(\"9.5\") = " + Double.valueOf("9.5"));
    }
}

Rezultat

note: [9, 10, 7], sumă: 26
Integer.MAX_VALUE = 2147483647
parseInt("2026") + 1 = 2027
Double.valueOf("9.5") = 9.5

Exemplul 2: Capcanele: == și null

Pentru valori între −128 și 127, Integer folosește obiecte din cache, deci == pare să meargă; pentru 1000 se creează obiecte diferite și == dă false. equals compară corect valorile. Unboxing-ul lui null aruncă excepție.

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        Integer a = 100, b = 100;
        Integer c = 1000, d = 1000;
        System.out.println("100 == 100: " + (a == b));
        System.out.println("1000 == 1000: " + (c == d));
        System.out.println("1000 equals 1000: " + c.equals(d));

        Map<String, Integer> stoc = new HashMap<>();
        stoc.put("mere", 12);
        Integer pere = stoc.get("pere"); // nu există: null
        System.out.println("pere: " + pere);
        try {
            int cantitate = pere;        // unboxing de null
            System.out.println(cantitate);
        } catch (NullPointerException e) {
            System.out.println("NullPointerException la unboxing");
        }
        int sigur = stoc.getOrDefault("pere", 0);
        System.out.println("cu getOrDefault: " + sigur);
    }
}

Rezultat

100 == 100: true
1000 == 1000: false
1000 equals 1000: true
pere: null
NullPointerException la unboxing
cu getOrDefault: 0

Greșeli frecvente

  • Compararea a două Integer cu ==: merge pentru valori mici (cache) și greșește pentru altele. Folosește equals sau despachetează în int.
  • Unboxing-ul unui null (de exemplu din map.get) aruncă NullPointerException.
  • Wrapper-e în bucle cu multe calcule (Long suma): fiecare pas creează un obiect nou și este mult mai lent decât long.

Comenzi înrudite

  • Variabile și tipuri primitive: O variabilă are un tip fix, declarat la creare; Java are 8 tipuri primitive: byte, short, int, long, float, double, char, boolean.
  • int, long, short și byte: Tipurile întregi din Java: int (32 de biți) pentru aproape orice, long pentru valori mari, short și byte pentru economie de memorie.
  • Generics (tipuri generice): Generics parametrizează clase și metode cu tipuri (List<String>, Map<String, Integer>), ca erorile de tip să apară la compilare, nu la rulare.
  • equals și hashCode: equals decide când două obiecte sunt „egale” ca valoare; hashCode trebuie rescris împreună cu el, altfel HashMap și HashSet nu funcționează corect.