Назад Зміст Вперед

5.4. Шаблони в Generic-аргументах методів

Шаблони аргументів (Джокер в Java Generics)

Шаблон аргументів вказується символом ? і являє собою невідомий тип. 
boolean sameAvg(Stats<?> ob) ... 

? (знак питання) символ представляє підстановлювальний елемент, тобто будь-який тип. Якщо ми пишемо <? extends Number>, це означає, що будь-який дочірній клас числа, наприклад, IntegerFloat, подвійний і т.д. І можна викликати метод класу Number через будь-який об'єкт класу object.

Приклад простого типу-контейнера Box, який підтримує операції put і get. 
Box параметризований параметром T.
public interface Box<T> 
 public T get(); 
 public void put(T element); 
}

Приклад методу unbox з wildcard-параметром (<?>)public void unbox (Box <?> box)
{
System.out.println (box.get ());
}

Цей параметр може викликати метод get (), а може - будь-який з методів, успадкованих від Object (наприклад, hashCode ()). Єдине, що він не може зробити - викликати метод put (), тому що без знання типу параметра T для даного екземпляра класу Box компілятор не в змозі перевірити цю операцію на безпеку (взагалі ж, викликати put () можна тільки в одному випадку: якщо передати туди null; ми можемо не знати, який тип представлений T, але зате знаємо, що літерал null є допустимим значенням для будь-якого заданого типу).

Що знає unbox () про тип значення, що повертається у метод box.get ()? Він знає, що це тип T для якогось невідомого T. Тому краще, що він може зробити - прийняти рішення, згідно з яким тип значення від get () є заміщенням невідомого раніше типу T. У разі необмеженого wildcard цей тип представлений типом Object . Таким чином, вираз box.get () в попередньому прикладі повертає значення типу Object.

Приклад.

import java.util.*;
abstract class Shape{
abstract void draw();
}
class Rectangle extends Shape{
void draw(){System.out.println("drawing rectangle");}
}
class Circle extends Shape{
void draw(){System.out.println("drawing circle");}
}
class GenericTest{
//creating a method that accepts only child class of Shape
public static void drawShapes(List<? extends Shape> lists){
for(Shape s:lists){
s.draw();//calling method of Shape class by child class instance
}
}
public static void main(String args[]){
List<Rectangle> list1=new ArrayList<Rectangle>();
list1.add(new Rectangle());

List<Circle> list2=new ArrayList<Circle>();
list2.add(new Circle());
list2.add(new Circle());

drawShapes(list1);
drawShapes(list2);
}}
Output:
drawing rectangle 
drawing circle 
drawing circle
.