Mechanizm rzutowania typów w Javie (type casting) pozwala programiście na jawne lub niejawne przekształcanie wartości jednego typu na inny. Historycznie cecha ta została odziedziczona z C i C++, ale w Javie jest ograniczona w celu zwiększenia bezpieczeństwa typów i zapobiegania ukrytym błędom związanym z przepełnieniem lub utratą danych.
Problem polega na możliwości wystąpienia ClassCastException podczas rzutowania typów odniesienia, a także na utracie precyzji podczas rzutowania typów prymitywnych, na przykład przy przejściu od double do int. Mogą wystąpić błędy logiczne podczas tzw. "downcastingu" (rzutowania na typ pochodny), jeśli instancja nie należy do tej klasy.
Rozwiązanie polega na ścisłym podziale:
Przykład kodu dla typów prymitywnych:
int i = 100; long l = i; // rzutowanie niejawne (int -> long) double d = l; // rzutowanie niejawne (long -> double) int i2 = (int) d; // rzutowanie jawne (utraty części ułamkowej)
Przykład kodu dla typów odniesienia:
Object obj = "Hello"; // upcasting, niejawnie String s = (String) obj; // downcasting, jawnie
Kluczowe cechy:
Czy kompilator Java może zapobiec wszelkim błędnym rzutowaniom typów?
Odpowiedź: Nie, kompilator wychwytuje tylko oczywiste błędy na etapie kompilacji. Jeśli rzutowanie jest możliwe w strukturze typów (na przykład, Object -> String), ale w zmiennej rzeczywiście znajduje się obiekt niezgodnego typu, błąd ujawnia się dopiero w czasie wykonania z ClassCastException.
Czy Integer dziedziczy po Long, i czy można zapisać Integer i = (Integer) someLong?
Odpowiedź: Nie, Integer i Long są niezależnymi klasami opakowującymi, między nimi nie można przeprowadzić downcastingu. Oba dziedziczą po Number, ale nie po sobie nawzajem. Rzutowanie w postaci (Integer) (Object) 1L; spowoduje ClassCastException.
Czy podczas jawnego rzutowania float na int następuje zaokrąglenie części ułamkowej?
Odpowiedź: Nie, następuje odrzucenie części ułamkowej bez zaokrąglenia:
float f = 3.99f; int i = (int) f; // i == 3, a nie 4
Programista otrzymuje kolekcję Object, rzutuje każdy element na swój typ, ale nie sprawdza instanceof. Projekt stabilnie kończy się z ClassCastException przy niepoprawnych danych.
Zalety:
Wady:
Wszystkie operacje downcastingu odbywają się wewnątrz if (obj instanceof TargetType) z wyraźnym przetwarzaniem błędów. Dla kolekcji stosowane są generyki.
Zalety:
Wady: