Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

СТП / lec / java2014-lec-08

.pdf
Скачиваний:
5
Добавлен:
03.03.2016
Размер:
809.22 Кб
Скачать

Подчистка типов и полиморфизм

//Это мостик для вызова родного метода public void setFirst(java.lang.Object); Code:

0: aload_0

1: aload_1

2: checkcast #4;//class java/util/Date

5: invokevirtual #6; //Method setFirst:(Ljava/util/Date;)V

8: return

//Это мостик для вызова родного метода

public java.lang.Object getFirst(); Code:

0: aload_0

1: invokevirtual #7;//Method getFirst:()Ljava/util/Date;

4: areturn }

Поэтому на самом деле вызываются по факту выполнения методы потомка,

что верно. Если вызвать по факту выполнения на объекте-родителе, то методы родителя.

Выбирать, какой метод будет вызван – «мостик» или родной – нельзя, это делает компилятор. В потомке для данного случая это будет всегда «мостик».

Ограничения обобщения

параметры типа не могут принимать простые типы

instanceof для переменных типа всегда возвращает

«сырой» тип

исключения обобщенного класса нельзя генерировать и перехватывать

массивы обобщенных типов не разрешены (вместо этого используйте ArrayList)

переменные типа не разрешены в статическом контексте обобщенных классов:

static Т first;

static Т method(T item);

нельзя создавать экземпляры обобщенных типов

(new Т())

Ограничение обобщения

При создании обобщений на основе родственных классов

связь между обобщенными классами не сохраняется.

Подстановки в типах параметров

class Pair <? extends Account>

Гарантии безопасности типов

1 public class TestTypeSafety {

2public static void main(String[] args) {

3List<CheckingAccount> lc = new ArrayList<CheckingAccount>();

5lc.add(new CheckingAccount("Fred")); // OK

6

lc.add(new SavingsAccount("Fred")); // Ошибка компиляции!

7

 

8// однако...

9CheckingAccount ca = lc.get(O);

10// Безопасно, приведение типов не нужно

11}

12}

Инвариантность обобщений

7List<Account> la;

8List<CheckingAccount> lc = new ArrayList<CheckingAccount>();

9List<SavingsAccount> ls = new ArrayList<SavingsAccount>();

11// Если это возможно…

12la = lc;

13la.add(new CheckingAccount (" Fred"));

15// то должно быть возможно и это

16la = ls;

17la.add(new CheckingAccount ("Fred"));

19// поэтому...

20SavingsAccount sa = ls.get(O); // ой!

По факту, выражение «la=lc;» является недопустимым,

потому что CheckingAccount является экземпляром Account,

однако ArrayList<CheckingAccount> не является экземпляром

ArrayList<Account>.

Решение инвариантности обобщений

6

public static void printNames (List <? extends Account> lea) {

7

for (int i=0; i < lea.size(); i++) {

8

System.out.println(lea.get(i).getNameO() ;

9}

10}

11

12 public static void main(String[] args) {

13List<CheckingAccount> lc = new ArrayList<CheckingAccount>();

14List<SavingsAccount> ls = new ArrayList<SavingsAccount>();

16printNames(lc);

17printNames(ls);

19// но...

20List<? extends Oject> leo = lc; //OK

21leo.add(new CheckingAccount ("Fred")) ; // Ошибка компиляции!

22}

Примеры использования обобщений

class Employer{};

class Manager extends Employer{} class Worker extends Employer{};

//-----------------------------------------------------------------

public class Main {

public static void main(String[] args){

List<? extends Employer> list1 = new ArrayList<Manager>() List<? extends Employer> list2 = new ArrayList<Worker>(); list1 = list2;

1ist1.add(new Manager()); Worker w = (Worker)list1.get(0);

}

}

//-----------------------------------------------------------------

public class Main {

public static void wain(String[] args) {

List<? super Manager> list1 = new ArrayList<Employer>(); List<? super Worker> list2 = new ArrayList<Employer>(); list1.add(new Manager());

1ist1.add(new Worker()); Manager m = list1.get(0);

}

}

Примеры использования подстановок

List<Integer> ls = new ArrayList<Integer>();

List<? extends Object> ls1 = new ArrayList<String>(); ls1 = ls;

Тут все корректно, так как шаблон – это всего лишь средство,

используемое при декларации, то есть мы как бы говорим компилятору, что допускаем по факту декларации любой список, обобщенный на любой тип, наследующий от Object.

Но самое главное – некоторый конкретный тип, какой именно, определяется по факту выполнения программы.

Присвоение корректно, так как по факту декларации

шаблоны обоих списков сходятся, наоборот – «ls=ls1» –

было бы уже нельзя.

Особенности подстановок и обобщений

Любой метод обобщенного класса, который принимает переменную типа,

всегда принимает конкретный тип, определяемый фактом создания

объекта. Так как на этапе компиляции конкретного типа нет, то

недопустимо использование любого метода, который принимает

переменную типа в качестве параметра.

Ведь Generic должен работать по определению с объектами только одного

конкретного типа, поэтому недопустимо разрешать, например, передачу в методы любого типа, удовлетворяющего какому-то условию, только конкретного типа. Но на этапе компиляции конкретный тип неизвестен,

поэтому допускать такую передачу нельзя вообще.

Поэтому ls1.add(new Object()); – ошибка и вообще, что угодно в качестве параметра – ошибка, так как в сигнатуре метода add присутствует переменная типа, а тип у нас получился по декларации шаблонный, то есть неконкретный. На его место нельзя подставить ни один конкретный тип с точки зрения безопасности кода.

Тут вы можете оставить комментарий к выбранному абзацу или сообщить об ошибке.

Оставленные комментарии видны всем.

Соседние файлы в папке lec