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

СТП / lec / java2014-lec-08

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

Ограничение типов переменных

На месте типа Т может оказаться любой тип, это может

привести к ошибкам. Например, если в коде обобщенного класса сортируются или сравниваются объекты типа Т, но реальный тип Т не реализует интерфейс Comparable и

компилятор не может это проверить.

Выход – ограничение типов переменных

public static <Т extends Comparable> T min(T[] a)

public static <T extends Comparable & Comparator> T min(T[] a)

(только один класс и много интерфейсов)

Ограничение типов переменных

Особенности:

1.Обобщенные типы существуют только на уровне компилятора.

2.Виртуальная машина ничего не знает об обобщенных типах.

3.После проверки компилятора выполняется

«зачистка» типа.

4.Все переменные типы приводятся к своим ограничителям. Если ограничителей нет, то к

Object

Ограничение типов переменных

public class Pair {

private Object first; private Object second; public Pair() {};

public Pair(Object first, Object second){}; public Object getFirst(){ return first; } public void setFirst(Object first){}

}

При зачистке операции приведения типов для

возвращаемых и передаваемых параметров

вставляются автоматически.

Для обобщенных методов также автоматически осуществляется подчистка.

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

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

public class Pair<T> { private T first; public Pair () {};

public Pair(T first){};

public T getFirst() { return first; }

public void setFirst(T first){ this.first = first;)

}

public class DatePair extends Pair<Date> { @Override

public void setFirst(Date first){}

}

public class Main {

public static void main (String[] args) { Pair<Date> pair;

DatePair datePair = new DatePair(); pair = datePair;

pair.setFirst(new Date());

}

}

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

На самом деле в классе DatePair нет переопределения

метода setFirst.

Вклассе будет два метода:

//пришел из родителя после подчистки void setFirst(Object first)

void setFirst(Date first)

Так как на этапе компиляции pair.setFirst(new Date)

ничего не знает о дочернем классе, то будет подставлен

поиск метода void setFirst(Object first), то есть метода

родителя, что нарушает принцип полиморфизма

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

Для решения этой проблемы компилятор

автоматически генерирует методы-мостики.

public void setFirst(Object first) { setFirst((Date)first);

}

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

Более «интересная» проблема возникает в таком случае:

в обобщенном родителе

– Т getFirst(){}

в дочернем классе

– Date getFirst(){}

После выполнения подчистки и наследования в

дочернем классе получаем:

Object getFirst(){} Date getFirst(){}

Два одинаковых метода с разными типами возврата запрещены, но разрешены – так как в виртуальной машине идентификатор метода включает и тип возвращаемого результата, то в данном случае компилятор пропустит код.

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

// Итак есть класс родитель public class ParentClass<T> {

private T first;

public T getFirst(){ return first; }

public void setFirst(T first){ this.first = first; }

}

//есть потомок

public class ChildrenClass extends ParentClass<Date>{ public Date getFirst(){ return new Date(); } public void setFirst(Date d){ }

}

// и класс Main public class Main {

public static void main(String[] args) { ParentClass<Date> p = new ParentClass<Date>(); ChildrenClass с = new ChildrenClass();

p = c;

p.setFirst(new Date()); p.getFirst();

}

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

Если дизассемблировать код классов, то увидим следующее.

Для Main.class:

public static void main(java.lang.StringQ); Code:

0:

new #2;

//class javaapplication19/ParentClass

3:

dup

 

4:

invokespecial #3; //Method javaapplication19/ParentClass."<init>":()V

7:

astore_1

 

8:

new #4;

//class javaapplication19/ChildrenClass

11: dup

 

12: invokespecial #5; //Method javaapplication19/ChildrenClass."<init>":()V

15: astore_2

 

16: aload_2

 

17: astore_1

 

18: aload_1

 

19: new #6;//class java/util/Date

22: dup

 

23: invokespecial

#7; //Method java/util/Date."<init>":()V

26: invokevirtual

#8; // Method javaapplication19/ParentClass.setFirst:(Ljava/lang/Object;)V

28: invokevirtual

#10;// Method javaapplication19/ParentClass.getFirst:()Ljava/lang/Object;

30: return

 

В строках 26 и 28 вызываются методы, которые содержат в сигнатуре Object

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

Теперь для класса потомка

public javaapplication19.ChildrenClass(); Code:

0: aload_0

1: invokespecial #1; //Method javaapplicationl 9/ParentClass."<init>":()V

4: return

// Это родной метод

public void setFirst(java.util.Date); Code:

0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;

3: aload_1

4: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V

7: return

// Это родной метод

public java.util.Date getFirst(); Code:

0: new #4; //class java/util/Date

3: dup

4: invokespecial #5; //Method java/util/Date."<init>":()V

7: areturn

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