Czy ktoś mógłby mi w prosty sposób wytłumaczyć, dlaczego niedozwolone jest tworzenie tablic typów generycznych?

- Rejestracja:około 20 lat
- Ostatnio:około 2 godziny
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:ponad 16 lat
- Ostatnio:około 2 miesiące
- Lokalizacja:Polska, Warszawa
- Postów:1058
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:około 19 lat
- Ostatnio:ponad 9 lat
- 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] );
}
}
Zarejestruj się i dołącz do największej społeczności programistów w Polsce.
Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.