Jelenlegi hely

15.2. Helyettesítő típus

Ahogy körbejárjuk a printAll metódus első változata által felvetett kérdést, leszögezhetjük, hogy a printAll paramétere egy gyűjtemény, melynek elemi típusa lehet bármi, amit Collection<?> formában leírhatunk:

public void printAll(Collection<?> c) {
    for (Object o : c) {
        System.out.println(o);
    }
}

A ?-es típus határozatlan típusként ismert. A gyűjteményből bármikor kiolvasható az objektum, mert a visszatérési érték mindig garantáltan Object. Azonban nem adható objektum a gyűjteményhez, mert a ? ismeretlen típust jelöl, és nem lehet egyértelműen tudni, hogy a hozzá adni kívánt objektum leszármazott típusa-e az ismeretlen típusnak. Az egyetlen kivétel a null, amely eleme minden típusnak.

Korlátozhatjuk (vagy kényszeríthetjük) is a helyettesítő típust valamely típus segítségével. A korlátozott helyettesítő típus akkor hasznos, mikor csak részben ismerjük a paramétereket. Például tegyük fel, hogy van egy osztály hierarchiánk geometriai alakzatokból (Shape), és ennek leszármazott típusaiból (Circle, Rectangle, és így tovább). A rajzoló program, ami ezekre az objektumokra hivatkozik, meghív egy drawAll nevű metódust, hogy egy gyűjteményt rajzoljon ezekből az alakzatokból:

public void drawAll(Collection<Shapes> shapes) {
    for (Shape s: shapes) {
        s.draw();
    }
}

Mivel láthattuk, hogy nem megengedett a Shape típus valamely leszármazott típusának (például a Circle) alkalmazása, ezért ez a metódus csak korlátozottan használható: például nem hívható meg a Collection<Circle> esetén. Hogy lehetővé tegyük a Shape típus valamely leszármazott típusának típus paraméterként való alkalmazását, kiterjeszthetjük az alakzatok gyűjtemény típus paraméterét helyettesítő típusként. De mivel tudjuk, hogy a típus paraméter valamilyen alakzat lesz, a helyettesítést korlátozhatjuk a Shape típusra a következőképpen:

void drawAll(Collection<? extends Shapes> shapes) { ... }

Ez lehetővé teszi a drawAll számára, hogy elfogadjon bármilyen, a Shape típus leszármazott típusából álló gyűjteményt.

Összefoglalva, a helyettesítő típus felső korlátozással specializálható a <? extends Type> módon, ezáltal megfelelővé téve az adott Type minden leszármazott típusához. A helyettesítő típust alulról is korlátozhatjuk. Egy alulról korlátozott helyettesítő a <? super Type> módon írható le, és a Type minden ősosztályára használható. Megfigyelhetjük, hogy továbbra sem lehetséges ismeretlen típusú gyűjteményhez objektumot hozzáadni, és ez nem lehetséges korlátozott, ismeretlen típusú gyűjtemény esetén sem.