Czy ktoś mógłby mi w prosty sposób wytłumaczyć, dlaczego niedozwolone jest tworzenie tablic typów generycznych?
Tablice typów generycznych(uogólnionych).
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
Tzn o co dokładnie chodzi? Tutaj jest pokazane parę rzeczy z generykami: http://stackoverflow.com/questions/529085/java-how-to-generic-array-creation
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Polska, Warszawa
- Postów: 1066
Krótko mówiąc dlatego, że tablica wymaga i identyfikuje typ swoich elementów podczas wykonania. Nakazując kompilatorowi stworzenie tablicy typu E - który podczas wykonania zaciera się - kompilator będzie musiał wyprodukować kod tworzący tablicę, która nie zna typu swoich elementów, który gdyby go zapisać wyglądałby tak: new ?[] (a to nie to samo co Object[]). Takiej tablicy nie można stworzyć z definicji i dlatego dostaje się błąd.
Można to obejść tworząc tablicę, której typem elementów jest najbliższa rama typu E (bez jej określenia jest to Object, czyli Object[]) i rzutując typ referencji do niej z jej rzeczywistego typu elementów na typ który powinna przechowywać. Rzutowanie takie można zrobić w jakiejś trywialnej metodzie final/private
np.:
@SuppressWarnings({"unchecked"}) private E[] cast(Object tab) { return (E[]) tab; }
dzięki czemu kompilator będzie się starał wbudowywać jej kod w miejscu wywołania (inline), a ponieważ jedyną jej instrukcją byłoby trywialne rzutowanie, to wygenerowany w miejscu wywołania kod nie będzie nawet istniał.
Uwaga. Argument tab nie może być typu Object[] ponieważ wspólnym przodkiem typów Object[] i E[] jest Object. Rzutowania E[]->Object->E[] udadzą się, a E[]->Object[]->E[] nie udadzą się, ponieważ Object[] i E[] pochodzą z dwóch różnych gałęzi dziedziczenia. Dla tego drugiego przypadku w C++ istnieje operator reinterpret_cast(), który w Javie nie istnieje i raczej nigdy nie powstanie.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 892
jeszcze krócej, to można bezczelnie powiedzieć, że skoro nie działa:
T a = new T();
to nie ma co wymagać, żeby działało
T[] a = new T[5];
Trudna sprawa ;) Jak napisał Olamagato, a warto naprawdę głośno krzyknąć: generics'y są w javie czasem uciążliwe, bo T jest usuwane w czasie kompilacji. I wszystkie Map<String,Float> są zamieniane na Map. Nawet nie na Map<Object,Object>, ale na surowe Map. Normalnie, żeby używać typu T, to trzeba przechowywać sobie w obiekcie jakoś samodzielnie informację o typie:
public class Generic<T> {
// tutaj przechowywać będziemy typ
Class<T> type;
public Generic(Class<T> type) {
// zapamiętujemy typ
this.type = type;
}
public T[] getArray(int size) {
// np tutaj tworzymy tablicę jakąś - akrobatycznie
return (T[])java.lang.reflect.Array.newInstance(type, size);
}
public static void main(String[] args) {
Generic<Float> generic = new Generic<Float>(Float.class);
// sprawdzić, czy działa
Float[] array = generic.getArray(4);
array[1] = 1.15f;
System.out.println( array[1].getClass() + " = " + array[1] );
}
}