Форум программистов, компьютерный форум, киберфорум
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
1

Почему для wildcard можно использовать только один класс/интерфейс

07.06.2014, 15:18. Показов 3240. Ответов 12
Метки нет (Все метки)

почему так недоспустимо писать
Java
1
List<? extends SomeClass & SomeInterface>
а так допустимо ?

Java
1
List<T extends SomeClass & SomeInterface>

P.S.
Читал это , но что-то пазл в голове до конца не сошёлся

Добавлено через 7 минут
и в обсуждениях дженериков часто употребляется слово capture. Не совсем понимаю его смысл.
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.06.2014, 15:18
Ответы с готовыми решениями:

Можно ли создать интерфейс, в котором один из методов будет возвращать класс, который реализует интерфейс
Можно ли создать интерфейс, в котором один из методов будет возвращать класс, который реализует...

Bitmap.BeginInit можно использовать только один раз?
Народ смотрите проблему, я хочу вывести список картинок ссылки на которые у меня находятся в...

Использовать интерфейс/абстрактный класс для оптимизации
Всем привет Как здесь лучше оптимизировать код, потому что повторяюсь. Не хочется выносить...

Написать класс, от которого можно получить только один экземпляр класса
Написать класс, от которого можно получить только один экземпляр класса. Как такое реализовать?...

12
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
09.06.2014, 23:34  [ТС] 2
up!
0
61 / 61 / 19
Регистрация: 06.09.2013
Сообщений: 236
Записей в блоге: 1
10.06.2014, 17:59 3
Тема обобщений довольна интересна. В данном случае, <?> - это шаблонный символ. Он используется тогда, когда мы хотим сказать - нам нужен любой совместимый с данным тип. Capture - это как раз и есть этот шаблон. Ниже приведу простой пример использования generic типов - простое сравнение чисел.

Оболочка числу:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class GenericWrap<T extends Number> {
    private T obj;
 
    public GenericWrap(T obj) {
        this.obj = obj;
 
        System.out.println("Generic type is " + obj.getClass().getTypeName());
        System.out.println("This value = " + obj);
    }
 
    public T getValue() {
        return obj;
    }
}
Вспомогательный класс со статическим методом для сравнения двух оболочек. Вернее, мы сравниваем их содержимое, как раз в параметре параметизированный тип для GenericWrap является шаблонный символ, то есть нам не важно - это Integer, Double или Short - нам нужен тип совместимый с <T extends Number>.
Java
1
2
3
4
5
class Util {
    public static Number compareWith(GenericWrap<?> one, GenericWrap<?> two) {
        return (one.getValue().doubleValue() > two.getValue().doubleValue()) ? one.getValue() : two.getValue();
    }
}
И сравнение в каком-то главном методе.
Java
1
2
3
4
        GenericWrap<Integer> a = new GenericWrap<Integer>(4);
        GenericWrap<Double> b = new GenericWrap<Double>(4.5);
 
        System.out.println(Util.compareWith(a, b));
Результат:
Java
1
2
3
4
5
6
7
8
9
10
// вывод из конструктора a 
Generic type is java.lang.Integer
This value = 4
 
// из конструктора b
Generic type is java.lang.Double
This value = 4.5
 
// результат сравнения
4.5
Шаблоны также можно сделать ограниченными, если в этом есть нужда. Так, например, если мы можем модифицировать метод compareWith() чтобы он сравнивал только оболочки с generic типом Integer.

Java
1
2
3
4
5
class Util {
    public static Number compareWith(GenericWrap<? extends Integer> one, GenericWrap<? extends Integer> two) {
        return (one.getValue().doubleValue() > two.getValue().doubleValue()) ? one.getValue() : two.getValue();
    }
}
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
10.06.2014, 19:46  [ТС] 4
Ну классно все конечно, только возникает вопрос а читали ли вы вопрос?
0
61 / 61 / 19
Регистрация: 06.09.2013
Сообщений: 236
Записей в блоге: 1
10.06.2014, 23:46 5
Oops. Действительно, мой промах.

Разбираемся с шаблонным символом как generic типом. То, что вы пытаетесь сделать - недопустимо, с точки зрения концепции типов. Смотрите, если вы объявите коллекцию, где тип расширял бы сразу и интерфейс A и B, то вы бы столкнулись с серьезными проблемами, когда захотели поработать с элементами этой коллекции. Допустим, вы бы хотели сделать нечто вроде получения первого элемента в списке (индекс 0), получить - получите, но дальше что? Вы не сможете объект связать с ни одной ссылкой, ведь вам бы потребовалась ссылка типа A & B, что не входит в концепцию типов Java.

Если бы вы использовали T, как generic тип, то в качестве ссылки вы бы указали T и смогли дальше работать с элементами коллекции.

Кстати говоря, по ссылке в обсуждениях об этом упоминалось.
Цитата

Good question. It took me a while to figure out.

Lets simplify your case: You are trying to do the same as if you declare a class that extends 2 interfaces, and then a variable that has as a type those 2 interfaces, something like this:

Java
1
2
3
  class MyClass implements Int1, Int2 { }
 
  Int1 & Int2 variable = new MyClass()
Of course, illegal. And this is equivalent to what you try to do with generics. What you are trying to do is:

Java
1
  List<? extends A & B> foobar;
But then, to use foobar, you would need to use a variable of both interfaces this way:

Java
1
  A & B element = foobar.get(0);
Which is not legal in Java. This means, you are declaring the elements of the list as beeing of 2 types simultaneously, and even if our brains can deal with it, Java language cannot.


А также официальная документация по этому поводу.
Кликните здесь для просмотра всего текста

4.9 Intersection Types An intersection type takes the form T1 & ... & Tn, n>0, where Ti, 1in, are type expressions. Intersection types arise in the processes of capture conversion (§5.1.10) and type inference (§15.12.2.7). It is not possible to write an intersection type directly as part of a program; no syntax supports this. The values of an intersection type are those objects that are values of all of the types Ti, for 1in.
1
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
11.06.2014, 02:00  [ТС] 6
Цитата Сообщение от Freedomen Посмотреть сообщение
Смотрите, если вы объявите коллекцию, где тип расширял бы сразу и интерфейс A и B, то вы бы столкнулись с серьезными проблемами, когда захотели поработать с элементами этой коллекции. Допустим, вы бы хотели сделать нечто вроде получения первого элемента в списке (индекс 0), получить - получите, но дальше что? Вы не сможете объект связать с ни одной ссылкой, ведь вам бы потребовалась ссылка типа A & B, что не входит в концепцию типов Java.
да, я видел, что такая тема там обсуждалась, но не могу осознать в чем проблема.

допустим мы объявляем класс генерик c таким ограничением
Java
1
<T extends Number & Comparable>
значит когда будем создавать экземпляр генерика, то это условие должно быть выполнено.

Ну то есть Integer например удовлетворяет этому условию
Java
1
new ...<Integer>...
Цитата Сообщение от Freedomen Посмотреть сообщение
вам бы потребовалась ссылка типа A & B,
ну в нашем случае это ссылка на на любой генерик наследник Number реализующий Comparable.

Добавлено через 26 минут
давайте так.
Java
1
List<? extends Number>
это либо
List<Number>
List<Integer>
List<Float>
List<Double>
ну и так далее
таким образом мы не знаем что это за коллекция точно и добавлять не можем ничего. Только чтение - producer в producer/consumer отношении. Это мало к делу относится ну и ладно....

Java
1
List<? extends Comparable>
это список любых сравниваемых элементов

Float
Integer
Double
....
почему бы их не пересечь то ?

....


Хм, может потому, что они друг другу "перпендикулярны" и не сходятся раньше Object ?

Ну то есть у нас нет такой ссылки которая обязательно и Number и Comparable и чтобы она покрывала все варианты. Ну за исключением Object, а это как-то не круто.


Блин, надеюсь меня кто-нибудь понял.

Добавлено через 14 минут
хотя про
Java
1
<? super Number>
я могу это тоже самое сказать, но это не мешает ему существовать.

такую коллекцию можно изменять. Что-то пазл не складывается
0
61 / 61 / 19
Регистрация: 06.09.2013
Сообщений: 236
Записей в блоге: 1
12.06.2014, 23:40 7
Цитата Сообщение от gredwhite Посмотреть сообщение
Ну то есть у нас нет такой ссылки которая обязательно и Number и Comparable и чтобы она покрывала все варианты. Ну за исключением Object, а это как-то не круто.
Вы близки к истине.
Надеюсь, код ниже прояснит ситуацию...

Java
1
2
3
4
5
6
7
8
class MyGen <T extends Number & Comparable> {
    public void doSomething() {
        List<T> myList = new ArrayList<T>();
        myList.add((T) new Integer(4));
        
        System.out.println(myList.get(0));
    }
}
Результат: 4.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
13.06.2014, 13:03  [ТС] 8
Freedomen, а что должен прояснить этот кусочек кода?
То, что результат 4 - очевидно.
0
61 / 61 / 19
Регистрация: 06.09.2013
Сообщений: 236
Записей в блоге: 1
13.06.2014, 15:39 9
Я надеялся, что вы поиграетесь с кодом подставляя шаблонный символ вместо T. Цель была показать узкую применимость шаблонного символа в generic типах.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
13.06.2014, 17:14  [ТС] 10
Понятно, что в некоторых случаях можно получить exception в runtime. Непонятно к чему Вы ведете
0
61 / 61 / 19
Регистрация: 06.09.2013
Сообщений: 236
Записей в блоге: 1
13.06.2014, 19:04 11
Я веду к тому, что применение шаблонного символа очень узко и когда вы его используете в данной ситуации, компилятор не может позволить вам сделать что-либо, что может повредить список, на который ссылается данная ссылка. Вы можете вызывать методы из элементов списка, но ничего добавить/изменить вы не можете. Разрешено манипулировать элементами списка, но нельзя ничего добавлять... Это все при условии, что список может существовать.

В вашем же случае список существовать не может, из-за концепций типов ссылок. Опять же - очень простая махинация, которая сразу все объясняет.

(Внимание! Все перечисленное ниже - из области научной фантастики! )

Вы объявили список.
Java
1
List<? extends A & B> list;
Теперь вопрос вам - как вы создадите объект ArrayList? Какой типизированный параметр вы будете использовать?

Если бы вместо шаблонного символа мы бы использовали T, то мы бы сделали так:
Java
1
list = new ArrayList<T>; // где T extends A & B
Проблема заключается в том, что вы не отрицаете возможность использования шаблонного символа (?) как типизированный параметр, что запрещено, ведь используя ? мы говорим:"Эй, компилятор, мне нужен любой класс, расширяющий этот". И если используя T параметр мы могли бы сделать так:

Java
1
T one = list.get(0); // works
То используя шаблонный символ все свелось бы к неподдерживаему синтаксису:

Java
1
A&B one = list.get(0); // unsupported syntax
Просто вы мыслите - что было бы если бы я подставил Integer, который по сути подошел бы под ограничение, тогда можно получить ссылку типа Integer, а не A & B. Но это не так! Разработчики мыслили глобально, хорошо, вариант описанный в предыдущем предложении реален, но не в контексте шаблонного символа - а что если вы захотите непосредственно в методе что-то сделать? Вы наверняка не знаете, что за тип будет применен программистом - Integer, Double, Short ... Тогда вам пришлось бы использовать A & B ссылку, что не поддерживается текущим синтаксисом Java.

Очень надеюсь, что эта тема станет более ясной!
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
14.06.2014, 21:00  [ТС] 12
Цитата Сообщение от Freedomen Посмотреть сообщение
Вы объявили список.

Java
1
List<? extends A & B> list;
Теперь вопрос вам - как вы создадите объект ArrayList?
Создаю List некоторого типа. на этапе компиляции проверяется удовлетворяет ли он условию в определении класса.
почему я обязательно должен его создавать?

Java
1
class MyClass extends A implements B{}
Java
1
2
3
4
MyClass myClass = new MyClass();
 
List<MyClass> list = new ArrayList<>();
list.add(myClass);
ну и этот list можно передать в метод, который принимает ссылку типа
Java
1
List<? extends A & B>

Цитата Сообщение от Freedomen Посмотреть сообщение
То используя шаблонный символ все свелось бы к неподдерживаему синтаксису:



Java
1
A&B one = list.get(0); // unsupported syntax
ну во первых можно написать Object
Во-вторых мы миримся с некоторыми ограничениями в wild card. в super wild card мы можем добавлять (>=)потомка границы, а из extends только читать из ссылки границы.

а "?" тоже только к Object приводится.

Но если бы можно было делать несколько границ для wild card это имхо повысило бы типизированность.

Добавлено через 2 минуты
Цитата Сообщение от Freedomen Посмотреть сообщение
Если бы вместо шаблонного символа мы бы использовали T, то мы бы сделали так:
Код Java(TM) 2 Platform Standard Edition 5.0
1
list = new ArrayList<T>; // где T extends A & B

хотя тут я Вашу мысль совсем не понял. Такой синтаксис в джава поддерживается
0
61 / 61 / 19
Регистрация: 06.09.2013
Сообщений: 236
Записей в блоге: 1
14.06.2014, 21:44 13
Цитата Сообщение от gredwhite Посмотреть сообщение
Создаю List некоторого типа. на этапе компиляции проверяется удовлетворяет ли он условию в определении класса.
почему я обязательно должен его создавать?
Код Java(TM) 2 Platform Standard Edition 5.0
1
class MyClass extends A implements B{}
Код Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
MyClass myClass = new MyClass();
List<MyClass> list = new ArrayList<>();
list.add(myClass);
ну и этот list можно передать в метод, который принимает ссылку типа
Код Java(TM) 2 Platform Standard Edition 5.0
1
List<? extends A & B>
К сожалению, трюк с ссылкой myClass не пройдет. Java не поддерживает множественное наследование. Если вы расширяете тип A, то вы наследуете все его публичные члены, все бы ничего, но сюда не влезает понятия интерфейса - реализуя интерфейс B, вы обязаны реализовать объявленные методы - вашим уникальным путем.

Цитата Сообщение от gredwhite Посмотреть сообщение
ну во первых можно написать Object
Во-вторых мы миримся с некоторыми ограничениями в wild card. в super wild card мы можем добавлять (>=)потомка границы, а из extends только читать из ссылки границы.
а "?" тоже только к Object приводится.
Если так сделать можно - не значит, что так делать надо, по крайней мере, в концепции языка Java на данный момент.

Цитата Сообщение от gredwhite Посмотреть сообщение
хотя тут я Вашу мысль совсем не понял. Такой синтаксис в джава поддерживается
Я просто хотел показать возможность такой ситуации, при использовании не шаблонного символа.

Это такая тема, где мы должны просто использовать допустимый синтаксис и технологии, построенные на нем. В этом плане возникает большой антагонизм, но в целом разработчики старались мыслить глобально и избегать возможных проблем с текущим синтаксисом. Пытаюсь оперировать текущим моментом - никто не знает, какие изменения произойдут с Java в ближайшие пять-десять лет. Я попытался объяснить это как я понимаю, но советую не зацикливаться на изучении логики мыслей программистов из Oracle - иногда она погреблена под большой толщей...
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.06.2014, 21:44

Почему при использовании Drag and Drop события можно использовать только рас к элементу ?
Есть Drag and Drop и события на &lt;div class=&quot;div1&quot; onmousedown=&quot;Listenn()&quot;&gt; (внутри div находяться...

Какие регистры для счётчика можно использовать и почему?
include '%fasm%/win64ax.inc' section '.code' executable start: sub rsp,8 ...

Можно ли сделать класс один для всех?
Доброго времени суток. Вопрос: можно ли сделать класс один для всех. Например: у меня есть класс...

Факториал. Использовать только одну функцию main и только один цикл
задача вообщем простая, но условия осложняют: \sum_{i=0}^{n-1} {x}_{i}/i! использовать только...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru