Jelenlegi hely

15.4. Általános típusok használata az öröklésben

A fejezetben már korábban tárgyalt Cat osztálynak tekintsük a getLitter nevű metódusát, melynek visszatérési értéke egy Cat objektumokból álló gyűjtemény:

public Collection getLitter(int size) {
    ArrayList litter = new ArrayList(size);
    for (int i = 0; i < size; i++) {
        litter.add(i, new Cat());
        return litter;
    }
}

Megfigyelhető, hogy a Collection objektum határozatlan típusú: a gyűjteményben lévő objektumok típusa nem meghatározott. Azonos helyzet állt fenn minden további metódusnál is, melyek objektumot adnak vissza, még mielőtt az általános típusok elérhetővé váltak volna a Java 5.0-ás verzióban.

Tegyük fel, hogy írunk egy programot Cats néven, mely ezt a visszatérési értéket adja át egy gyűjteménynek, melynek típusa kifejezetten Cat kell, hogy legyen:

public static void main(String[] args) {
Collection<Cat> litter = myCat.getLitter(3);
for (Cat c : litter) {
    System.out.println(c.getColor());
}

Mikor lefordítja a Cats.java állományt, a következő figyelmeztetést kapja:

A Cats.java ellenőrizetlen vagy nem biztonságos műveleteket használ. Fordítsa le újra a -Xlint:unchecked
kapcsolóval a részletek megtekintéséhez.

Az Xlint:checked kapcsoló használata információgyűjtéshez:

% javac -Xlint:unchecked Cats.java
Cats.java:5: warning: [unchecked] unchecked conversion
found : java.util.Collection
required: java.util.Collection
Collection litter = myCat.getLitter(3);
^
Összegezve, ha a Cat-et olyan fordítóval fordítjuk újra, mely támogatja a típus paramétereket, a következő figyelmeztetést kapjuk:

% javac -Xlint:unchecked Cat.java
Cat.java:19: warning: [unchecked] unchecked call to
add(int,E) as a member of the raw type java.util.ArrayList
                                 litter.add(i, new Cat());
                                           ^

Habár a kód hibátlan, ez a figyelmeztetés mutatja, hogy a fordító nem tudja biztosítani a művelet pontosságát, mikor speciális típusú gyűjteményeket használunk. Amikor „ellenőrizetlen” figyelmeztetést kap, ellenőriznie kell, hogy a művelet, mely a figyelmeztetést generálta, valóban megfelelő-e.

Végül tekintsünk át egy listát a teljes Stack2 osztályról:

public class Stack2<T> implements Cloneable {
    private ArrayList<T> items;
    private int top=0;
    public Stack2() {
        items = new ArrayList<T>();
    }
    public void push(T item) {
        items.add(item);
        top++;
    }
    public T pop() {
        if (items.size() == 0)
        throw new EmptyStackException();
        T obj = items.get(--top);
        return obj;
    }
    public boolean isEmpty() {
        if (items.size() == 0)
            return true;
        else
            return false;
    }
    protected Stack2<T> clone() {
        try {
            Stack2<T> s = (Stack2<T>)super.clone();
            s.items =  (ArrayList<T>)items.clone();
            return s; // Return the clone
        } catch (CloneNotSupportedException e) {
            throw new InternalError();
        }
    }
}

Megfigyelhetjük, hogy a clone metódus a clone metódusokat az ősosztályából és a tartalmazott listájából hívja meg. A clone metódusok öröklődő metódusok, mert még az általános típusok elérhetősége előtt definiálva lettek.

Mikor lefordítja a Stack2.java állományt, a következő figyelmeztetést kapja:

% javac -Xlint:unchecked Stack2.java
Stack2.java:32: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: Stack2<T>
         Stack2<T> s = (Stack2<T>)super.clone();
                                             ^
Stack2.java:33: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: java.util.ArrayList<T>
         s.items =  (ArrayList<T>)items.clone();
                                             ^
2 warnings

Ez a figyelmeztetés mutatja, hogy a fordító nem képes biztosítani az eljárás kifogástalan működését. Más szóval, mivel a clone metódust úgy definiálták, hogy egy Object osztálybeli objektumot adjon visszatérési értéknek, ezért a fordító nem tudja biztosítani, hogy a gyűjtemény visszatérési értéke Stack2<T> legyen. Azonban a clone metódus feletti megállapodás szerint a művelet engedélyezett, habár „ellenőrizetlen” figyelmeztetést okoz.

Rengeteg apró dologra kell figyelni az általános típusok használatánál az öröklésben.

Ellenőrző kérdések

  • Mikor érdemes típus paramétert alkalmazni?
  • Mi az előnye a típus paraméter alkalmazásának?