Tablice typów generycznych(uogólnionych).

0

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

1

Tzn o co dokładnie chodzi? Tutaj jest pokazane parę rzeczy z generykami: http://stackoverflow.com/questions/529085/java-how-to-generic-array-creation

0

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.

0

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] );
    }
    
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1