Pytania:
- Jakie są typy raw w Javie i dlaczego często słyszę, że nie powinny być używane w nowym kodzie?
- Jaka jest alternatywa, jeśli nie możemy używać typów surowych i jak jest lepsza?
Odpowiedzi:
Specyfikacja języka Java definiuje typ surowy w następujący sposób:
Typ surowy jest zdefiniowany jako jeden z:
Typ odwołania, który jest tworzony przez przyjęcie nazwy ogólnej deklaracji typu bez towarzyszącej listy argumentów typu.
Typ tablicy, której typ elementu jest typem surowym.
Typ nienależący do
static
typu surowego,R
który nie jest dziedziczony z nadklasy lub superinterfejsuR
.
Oto przykład ilustrujący:
public class MyType<E> {
class Inner { }
static class Nested { }
public static void main(String[] args) {
MyType mt; // warning: MyType is a raw type
MyType.Inner inn; // warning: MyType.Inner is a raw type
MyType.Nested nest; // no warning: not parameterized type
MyType<Object> mt1; // no warning: type parameter given
MyType<?> mt2; // no warning: type parameter given (wildcard OK!)
}
}
Tutaj MyType<E>
jest typ sparametryzowany ( JLS 4.5 ). Zwykle potocznie określa się ten typ jako po prostu MyType
w skrócie, ale technicznie nazwa to MyType<E>
.
mt
ma typ raw (i generuje ostrzeżenie o kompilacji) na podstawie pierwszego punktu w powyższej definicji; inn
ma również typ surowy według trzeciego punktu.
MyType.Nested
nie jest sparametryzowanym typem, nawet jeśli jest to typ członka sparametryzowanego typu MyType<E>
, ponieważ jest static
.
mt1
, i mt2
oba są zadeklarowane za pomocą rzeczywistych parametrów typu, więc nie są to typy surowe.
Zasadniczo typy surowe zachowują się tak, jak przed wprowadzeniem leków generycznych. Oznacza to, że w czasie kompilacji poniższe informacje są całkowicie legalne.
List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!
Powyższy kod działa dobrze, ale załóżmy, że masz również:
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
Teraz napotykamy problemy w czasie wykonywania, ponieważ names
zawiera coś, co nie jest instanceof String
.
Można przypuszczać, że jeśli chcesz, names
aby zawierał tylko String
, to mógłby być może nadal korzystać typ surowca i ręcznie sprawdzić każdy add
samodzielnie, a następnie ręcznie odlewane do String
każdego elementu z names
. Jeszcze lepiej , chociaż NIE należy używać surowego typu i pozwolić kompilatorowi wykonać całą pracę za Ciebie , wykorzystując moc generycznych programów Java.
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
Oczywiście, jeśli NIE chcesz names
, aby umożliwić Boolean
, po czym można je zadeklarować jak List<Object> names
i powyższy kod będzie kompilować.
<Object>
jako parametrów typu?Oto cytat z Effective Java 2nd Edition, pozycja 23: Nie używaj surowych typów w nowym kodzie :
Jaka jest różnica między typem surowym
List
a typem sparametryzowanymList<Object>
? Mówiąc luźniej, ten pierwszy zrezygnował z ogólnego sprawdzania typów, podczas gdy ten drugi wyraźnie powiedział kompilatorowi, że jest w stanie pomieścić obiekty dowolnego typu. Chociaż można przekazać aList<String>
do parametru typuList
, nie można go przekazać do parametru typuList<Object>
. Istnieją reguły podtypów dla rodzajów ogólnych iList<String>
jest to podtyp typu surowegoList
, ale nie typu sparametryzowanegoList<Object>
. W rezultacie tracisz bezpieczeństwo typu, jeśli używasz typu surowegoList
, ale nie, jeśli używasz typu sparametryzowanegoList<Object>
.
Aby zilustrować tę kwestię, rozważ następującą metodę, która bierze List<Object>
a dodaje a new Object()
.
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Ogólne w Javie są niezmienne. A List<String>
nie jest a List<Object>
, więc poniższe wygeneruje ostrzeżenie kompilatora:
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
Gdybyś zadeklarował, appendNewObject
że List
jako parametr użyjesz surowego typu , to się skompiluje, a zatem stracisz bezpieczeństwo typu, które otrzymujesz od generycznych.
<?>
jako parametru typu?List<Object>
, List<String>
itd. są wszystkie List<?>
, więc kuszące może być stwierdzenie, że są po prostu List
. Jest jednak zasadnicza różnica: ponieważ List<E>
tylko definicja add(E)
, nie można dodać dowolnego obiektu do List<?>
. Z drugiej strony, ponieważ typ surowy List
nie ma bezpieczeństwa typu, możesz zrobić add
prawie wszystko List
.
Rozważ następującą odmianę poprzedniego fragmentu:
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
Kompilator wykonał wspaniałą pracę, chroniąc cię przed potencjalnym naruszeniem niezmienności typu List<?>
! Jeśli zadeklarujesz parametr jako typ surowy List list
, kod skompiluje się i naruszysz niezmiennik typu List<String> names
.
Powrót do JLS 4.8:
Możliwe jest użycie jako typu skasowania sparametryzowanego typu lub skasowania typu tablicowego, którego typem elementu jest sparametryzowany typ. Taki typ nazywany jest typem surowym .
[...]
Nadklasy (odpowiednio superinterfaces) typu surowego są wymazaniami nadklas (superinterfaces) dowolnej parametryzacji typu ogólnego.
Typ konstruktora, metoda instancji lub niepola
static
typu surowego,C
który nie jest dziedziczony z jego nadklas lub superinterfejsów, jest typem surowym, który odpowiada usunięciu jego typu w ogólnej deklaracji odpowiadającejC
.
Mówiąc prościej, gdy używany jest typ surowy, konstruktory, metody instancji i niepole static
są również usuwane .
Weź następujący przykład:
class MyType<E> {
List<String> getNames() {
return Arrays.asList("John", "Mary");
}
public static void main(String[] args) {
MyType rawType = new MyType();
// unchecked warning!
// required: List<String> found: List
List<String> names = rawType.getNames();
// compilation error!
// incompatible types: Object cannot be converted to String
for (String str : rawType.getNames())
System.out.print(str);
}
}
Kiedy używamy surowego MyType
, getNames
zostaje również wymazany, dzięki czemu zwraca surowe List
!
JLS 4.6 nadal wyjaśnia, co następuje:
Usuwanie typu mapuje również sygnaturę konstruktora lub metody na sygnaturę, która nie ma sparametryzowanych typów ani zmiennych typów. Kasowanie sygnatury konstruktora lub metody
s
jest sygnaturą składającą się z tej samej nazwys
i kasowania wszystkich formalnych typów parametrów podanych ws
.Typ zwracany przez metodę i parametry typu ogólnej metody lub konstruktora również są usuwane, jeśli metoda lub podpis konstruktora zostaną usunięte.
Usunięcie podpisu metody ogólnej nie ma parametrów typu.
Poniższy raport o błędach zawiera przemyślenia Maurizio Cimadamore, twórcy kompilatora i Alexa Buckley'a, jednego z autorów JLS, na temat tego, dlaczego takie zachowanie powinno nastąpić: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Krótko mówiąc, upraszcza to specyfikację).
Oto kolejny cytat z JLS 4.8:
Użycie typów surowych jest dozwolone tylko jako ustępstwo do zgodności ze starszym kodem. Użycie typów surowych w kodzie napisanym po wprowadzeniu generyczności do języka programowania Java jest zdecydowanie odradzane. Możliwe, że przyszłe wersje języka programowania Java nie zezwalają na stosowanie typów surowych.
Efektywna Java 2. edycja ma również tę opcję:
Biorąc pod uwagę, że nie powinieneś używać typów surowych, dlaczego projektanci języków na to zezwolili? Aby zapewnić zgodność.
Platforma Java miała wkroczyć w drugą dekadę, kiedy wprowadzono generyczne, i istniała ogromna ilość kodu Java, który nie korzystał z generycznych. Uznano za krytyczne, że cały ten kod pozostaje legalny i interoperacyjny z nowym kodem, który używa generycznych. Musi być legalne przekazywanie wystąpień sparametryzowanych typów do metod zaprojektowanych do użycia ze zwykłymi typami i odwrotnie. Ten wymóg, znany jako kompatybilność migracji , podjął decyzję o wsparciu typów surowych.
Podsumowując, typy surowe NIGDY nie powinny być używane w nowym kodzie. Zawsze powinieneś używać sparametryzowanych typów .
Niestety, ponieważ generyczne Java nie są weryfikowane, istnieją dwa wyjątki, w których typy surowe muszą być użyte w nowym kodzie:
List.class
NieList<String>.class
instanceof
operand, np. o instanceof Set
nieo instanceof Set<String>
o instanceof Set<?>
jest również dozwolona w celu uniknięcia typu surowego (choć w tym przypadku jest to tylko powierzchowne).
n
zdalnych komponentów bean dla każdej klasy implementującej z identycznym kodem.
TypeName.class
, gdzie TypeName
jest zwykły identyfikator ( jls ). Mówiąc hipotetycznie, myślę, że tak może być. Być może jako wskazówka List<String>.class
jest wariant, który JLS nazywa konkretnie błędem kompilatora, więc jeśli kiedykolwiek dodadzą go do języka, spodziewam się, że to ten, którego używają.
Jakie są typy raw w Javie i dlaczego często słyszę, że nie powinny być używane w nowym kodzie?
Surowe typy to starożytna historia języka Java. Na początku były Collections
i nie posiadały Objects
nic więcej i nic mniej. Każda operacja na Collections
wymaganych rzutach od Object
do pożądanego typu.
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
Chociaż działało to przez większość czasu, błędy się zdarzały
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
Stare beztypowe kolekcje nie mogły wymuszać bezpieczeństwa typu, więc programista musiał pamiętać, co przechował w kolekcji.
Gdy opracowano ogólne, aby obejść to ograniczenie, programista zadeklaruje typ przechowywany jeden raz, a kompilator zrobi to zamiast tego.
List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine
Dla porownania:
// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings
Bardziej złożony interfejs porównywalny:
//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
int id;
public int compareTo(Object other)
{return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
int id;
public int compareTo(MyCompareAble other)
{return this.id - other.id;}
}
Zauważ, że nie można zaimplementować CompareAble
interfejsu z compareTo(MyCompareAble)
typami raw. Dlaczego nie powinieneś ich używać:
Object
przechowywane w a Collection
muszą zostać oddane przed użyciemObject
Co robi kompilator: Generics są wstecznie kompatybilne, używają tych samych klas java co surowe typy. Magia dzieje się głównie w czasie kompilacji.
List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);
Zostanie skompilowany jako:
List someStrings = new ArrayList();
someStrings.add("one");
String one = (String)someStrings.get(0);
Jest to ten sam kod, który napisałbyś, gdybyś używał typów surowych bezpośrednio. Pomyślałem, że nie jestem pewien, co dzieje się z CompareAble
interfejsem, myślę, że tworzy on dwie compareTo
funkcje, jedna bierze MyCompareAble
a druga bierze Object
i przekazuje do pierwszej po rzuceniu.
Jakie są alternatywy dla typów surowych: Użyj generycznych
Typ surowy to nazwa ogólnej klasy lub interfejsu bez żadnych argumentów typu. Na przykład biorąc pod uwagę ogólną klasę Box:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Aby utworzyć sparametryzowany typ Box<T>
, podajesz argument typu rzeczywistego dla formalnego parametru typu T
:
Box<Integer> intBox = new Box<>();
Jeśli argument typu rzeczywistego zostanie pominięty, tworzony jest surowy typ Box<T>
:
Box rawBox = new Box();
Dlatego Box
jest typem surowym typu ogólnego Box<T>
. Jednak nie ogólna klasa lub typ interfejsu nie jest typem surowym.
Typy surowe pojawiają się w starszym kodzie, ponieważ wiele klas API (takich jak klasy Kolekcje) nie było ogólnych przed JDK 5.0. Używając typów surowych, zasadniczo uzyskujesz zachowanie przedgeneryczne - a Box
daje ci Object
s. W celu zachowania zgodności wstecznej dozwolone jest przypisywanie sparametryzowanego typu do jego typu surowego:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
Ale jeśli przypiszesz typ surowy do sparametryzowanego typu, pojawi się ostrzeżenie:
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
Pojawia się również ostrzeżenie, jeśli używasz typu raw do wywoływania metod ogólnych zdefiniowanych w odpowiednim typie ogólnym:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
Ostrzeżenie pokazuje, że typy surowe omijają ogólne sprawdzanie typów, odraczając przechwytywanie niebezpiecznego kodu do środowiska wykonawczego. Dlatego należy unikać używania typów surowych.
Sekcja Usuwanie typu zawiera więcej informacji o tym, w jaki sposób kompilator Java wykorzystuje typy surowe.
Jak wspomniano wcześniej, podczas mieszania starszego kodu z kodem ogólnym mogą pojawić się komunikaty ostrzegawcze podobne do następujących:
Uwaga: Example.java używa niesprawdzonych lub niebezpiecznych operacji.
Uwaga: Ponowna kompilacja z opcją -Xlint: niezaznaczone dla szczegółów.
Może się to zdarzyć przy użyciu starszego interfejsu API działającego na typach raw, jak pokazano w poniższym przykładzie:
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
Termin „niezaznaczony” oznacza, że kompilator nie ma wystarczających informacji o typie, aby wykonać wszystkie kontrole typu niezbędne do zapewnienia bezpieczeństwa typu. Ostrzeżenie „niezaznaczone” jest domyślnie wyłączone, choć kompilator daje podpowiedź. Aby zobaczyć wszystkie „niezaznaczone” ostrzeżenia, ponownie skompiluj z opcją -Xlint: niezaznaczone.
Ponowna kompilacja poprzedniego przykładu z opcją -Xlint: niezaznaczone ujawnia następujące dodatkowe informacje:
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
Aby całkowicie wyłączyć niesprawdzone ostrzeżenia, użyj flagi -Xlint: -unchecked. @SuppressWarnings("unchecked")
Adnotacja tłumi niezaznaczone ostrzeżenia. Jeśli nie znasz @SuppressWarnings
składni, zobacz Adnotacje.
Oryginalne źródło: Poradniki Java
„Surowy” typ w Javie to klasa, która nie jest ogólna i zajmuje się „surowymi” obiektami, a nie bezpiecznymi dla typu parametrami typu ogólnego.
Na przykład przed udostępnieniem ogólnych składników Java należy użyć klasy kolekcji takiej jak ta:
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
Kiedy dodajesz swój obiekt do listy, nie ma znaczenia, jaki to jest typ obiektu, a kiedy pobierzesz go z listy, musisz jawnie rzutować go na oczekiwany typ.
Używając ogólnych, usuwasz czynnik „nieznany”, ponieważ musisz jawnie określić, jaki typ obiektów może znaleźć się na liście:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
Zauważ, że w przypadku ogólnych nie musisz rzutować obiektu pochodzącego z wywołania get, kolekcja jest wstępnie zdefiniowana do pracy tylko z MyObject. Ten fakt jest głównym czynnikiem napędzającym leki generyczne. Zmienia źródło błędów w czasie wykonywania na coś, co można sprawdzić podczas kompilacji.
?
nadal zapewnia bezpieczeństwo typu. Omówiłem to w swojej odpowiedzi.
private static List<String> list = new ArrayList<String>();
Powinieneś określić parametr typu.
Ostrzeżenie informuje, że typy zdefiniowane do obsługi rodzajów ogólnych powinny zostać sparametryzowane, a nie przy użyciu ich surowej postaci.
List
jest zdefiniowana generycznych wsparcia: public class List<E>
. Pozwala to na wiele bezpiecznych operacji, które są sprawdzane podczas kompilacji.
private static List<String> list = new ArrayList<>();
Co to jest typ raw i dlaczego często słyszę, że nie należy ich używać w nowym kodzie?
„Typ surowy” to użycie klasy ogólnej bez określania argumentów typu dla sparametryzowanych typów, np. Użycie List
zamiast List<String>
. Kiedy w Javie wprowadzono leki generyczne, zaktualizowano kilka klas, aby korzystały z nich. Użycie tych klas jako „typu surowego” (bez podania argumentu typu) pozwoliło na kompilację starszego kodu.
„Typy surowe” są używane dla kompatybilności wstecznej. Ich użycie w nowym kodzie nie jest zalecane, ponieważ użycie klasy ogólnej z argumentem typu pozwala na silniejsze pisanie, co z kolei może poprawić zrozumiałość kodu i prowadzić do wcześniejszego wychwytywania potencjalnych problemów.
Jaka jest alternatywa, jeśli nie możemy używać typów surowych i jak jest lepsza?
Preferowaną alternatywą jest użycie klas ogólnych zgodnie z przeznaczeniem - z argumentem odpowiedniego typu (np List<String>
.). Pozwala to programiście na bardziej precyzyjne określenie typów, przekazuje przyszłym opiekunom więcej znaczenia na temat zamierzonego zastosowania zmiennej lub struktury danych, a także pozwala kompilatorowi wymusić lepsze bezpieczeństwo typu. Te zalety łącznie mogą poprawić jakość kodu i pomóc zapobiec wprowadzeniu niektórych błędów kodowania.
Na przykład dla metody, w której programista chce się upewnić, że zmienna List o nazwie „names” zawiera tylko ciągi znaków:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
polygenelubricants
„surowe” referencje z stackoverflow.com/questions/2770111/... do mojej własnej odpowiedzi, ale przypuszczam, że zostawię je do użycia we własnej odpowiedzi.
Kompilator chce, abyś napisał:
private static List<String> list = new ArrayList<String>();
ponieważ w przeciwnym razie możesz dodać dowolny typ list
, co sprawia, że tworzenie instancji jest new ArrayList<String>()
bezcelowe. Generyczne elementy języka Java są tylko funkcją czasu kompilacji, więc obiekt utworzony za pomocą new ArrayList<String>()
tego elementu chętnie zaakceptuje elementy Integer
lub JFrame
elementy, jeśli zostaną przypisane do odwołania do „typu surowego” List
- sam obiekt nie wie nic o typach, które powinien zawierać, tylko kompilator.
Rozważam wiele przypadków, w których można wyjaśnić tę koncepcję
1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();
ArrayList<String> arr
jest to ArrayList
zmienna referencyjna z typem, String
która odnosi się do ArralyList
obiektu typu String
. Oznacza to, że może przechowywać tylko obiekt typu String.
Nie jest String
typem surowym, więc nigdy nie wywoła ostrzeżenia.
arr.add("hello");// alone statement will compile successfully and no warning.
arr.add(23); //prone to compile time error.
//error: no suitable method found for add(int)
W tym przypadku ArrayList<String> arr
jest to typ ścisły, ale Twój obiekt new ArrayList();
jest typem surowym.
arr.add("hello"); //alone this compile but raise the warning.
arr.add(23); //again prone to compile time error.
//error: no suitable method found for add(int)
tutaj arr
jest typ ścisły. Tak więc podniesie błąd czasu kompilacji podczas dodawania integer
.
Ostrzeżenie : -
Raw
Obiekt typu odwołuje się doStrict
typu Zmienna referencyjna typuArrayList
.
W tym przypadku ArrayList arr
jest to typ surowy, ale twój obiekt new ArrayList<String>();
jest typem ścisłym.
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
Doda do niego dowolny typ obiektu, ponieważ arr
jest to typ surowy.
Ostrzeżenie : -
Strict
Obiekt typu odwołuje się doraw
typu Zmienna.
Typ surowy to brak parametru typu, gdy używany jest typ ogólny.
Raw typu nie powinny być stosowane, ponieważ może to spowodować błędy wykonawcze, jak wstawiając double
w to, co miało być Set
od int
s.
Set set = new HashSet();
set.add(3.45); //ok
Podczas odzyskiwania rzeczy z Set
, nie wiesz, co wychodzi. Załóżmy, że oczekujesz, że to będzie wszystko int
, do czego rzucasz Integer
; wyjątek w czasie wykonywania, gdy double
pojawi się wersja 3.45.
Po dodaniu do parametru parametru typuSet
od razu pojawi się błąd kompilacji. Ten zapobiegawczy błąd pozwala naprawić problem, zanim coś wybuchnie podczas działania (oszczędzając w ten sposób czas i wysiłek).
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
Oto kolejny przypadek, w którym gryzą cię surowe typy:
public class StrangeClass<T> {
@SuppressWarnings("unchecked")
public <X> X getSomethingElse() {
return (X)"Testing something else!";
}
public static void main(String[] args) {
final StrangeClass<String> withGeneric = new StrangeClass<>();
final StrangeClass withoutGeneric = new StrangeClass();
final String value1,
value2;
// Compiles
value1 = withGeneric.getSomethingElse();
// Produces compile error:
// incompatible types: java.lang.Object cannot be converted to java.lang.String
value2 = withoutGeneric.getSomethingElse();
}
}
Jak wspomniano w zaakceptowanej odpowiedzi, tracisz wszelką obsługę generyków w kodzie surowego typu. Każdy parametr typu jest konwertowany na jego skasowanie (co w powyższym przykładzie jest po prostu Object
).
Chodzi o to, że twój list
jestList
nieokreślonym przedmiotem. Oznacza to, że Java nie wie, jakie obiekty znajdują się na liście. Następnie, gdy chcesz iterować listę, musisz rzucić każdy element, aby mieć dostęp do właściwości tego elementu (w tym przypadku String).
Zasadniczo lepiej jest sparametryzować kolekcje, więc nie masz problemów z konwersją, będziesz mógł dodawać tylko elementy sparametryzowanego typu, a Twój edytor zaoferuje odpowiednie metody wyboru.
private static List<String> list = new ArrayList<String>();
Typ surowy to nazwa ogólnej klasy lub interfejsu bez żadnych argumentów typu. Na przykład biorąc pod uwagę ogólną klasę Box:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Aby utworzyć sparametryzowany typ pola, podajesz argument typu rzeczywistego dla formalnego parametru typu T:
Box<Integer> intBox = new Box<>();
Jeśli argument typu rzeczywistego zostanie pominięty, tworzony jest surowy typ pola:
Box rawBox = new Box();
Unikaj surowych typów
Typy surowe odnoszą się do używania typu ogólnego bez określania parametru typu.
Na przykład ,
Lista jest typem surowym, a List<String>
typem sparametryzowanym.
Kiedy w JDK 1.5 wprowadzono generics, surowe typy zostały zachowane tylko w celu zachowania kompatybilności wstecznej ze starszymi wersjami Javy. Mimo że używanie typów surowych jest nadal możliwe,
Należy ich unikać :
Są mniej wyraziste i nie dokumentują się w taki sam sposób jak sparametryzowane typy Przykład
import java.util.*;
public final class AvoidRawTypes {
void withRawType() {
//Raw List doesn't self-document,
//doesn't state explicitly what it can contain
List stars = Arrays.asList("Arcturus", "Vega", "Altair");
Iterator iter = stars.iterator();
while (iter.hasNext()) {
String star = (String) iter.next(); //cast needed
log(star);
}
}
void withParameterizedType() {
List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
for (String star: stars) {
log(star);
}
}
private void log(Object message) {
System.out.println(Objects.toString(message));
}
}
W celach informacyjnych : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
Znalazłem tę stronę po kilku przykładowych ćwiczeniach i dokładnie takiej samej zagadce.
============== Poszedłem z tego kodu, jak zapewnia przykład ===============
public static void main(String[] args) throws IOException {
Map wordMap = new HashMap();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
====================== Do tego kodu ========================
public static void main(String[] args) throws IOException {
// replace with TreeMap to get them sorted by name
Map<String, Integer> wordMap = new HashMap<String, Integer>();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
Entry<String, Integer> entry = i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
}
================================================== =============================
Może być bezpieczniej, ale demontaż filozofii zajął 4 godziny ...
Surowe typy są w porządku, gdy wyrażają to, co chcesz wyrazić.
Na przykład funkcja deserializacji może zwrócić a List
, ale nie zna typu elementu listy. Tak List
jest tutaj odpowiedni typ zwrotu.