[java 1.6] Generic конструктор.
public <V extends RandomAccess & List<T> > RingList(@NotNull V underlayingList) {
entry = underlayingList;
}
а во-вторых TreeList (не generic).TreeList который из commons-collections? он экстендит AbstractList
Да, но экстендит его без параметризации элементов.
Это нормально
Ваще не понимаю.
И твой вариант конструктора его резонно не пускает.
по ходу действительно какой-то баг
ждем гуру явы
Может, это из-за type erasure?
Вот только не очень понятно, как порядок объявления в списке extends может влиять на результат компиляции
public RingList(List underlayingList)
а после изменения порядка перечисления границ raw-конструктор станет
public RingList(RandomAccess underlayingList)
а что, в метаданных все эти списки ограничений не хранятся и компилятором не проверяются?
Может, я чего-то не понимаю, обесните. Как это вообще так? Вот дотнетовский компайлер — тупо сохраняет все произведённые в компайл тайм инстанциации генериков при помощи символа "`" и перечисления параметров после него, ещё сохраняет немножко метаданных про сам темплейт (которыми всё равно никто никогда не пользуется) и всё прекрасно, участие со стороны CLR не требуется.
Как вообще могло получиться то, что получилось в жаве? Один знакомый сказал, что это от того, что не хотели менять JVM ещё раз, но бля, я не понимаю, можно же было её и не менять! Сейчас-то полная порнография получается, я раньше думал, что они просто стирают тайп информейшен о генерик параметрах, проверяют, что не случается оверлоадинг конфликтов и всё. А тут вдруг выясняется, что есть ещё какие-то правила. Зачем?
18.03.2008 2:14 ICQ: а
18.03.2008 2:14 ICQ: хаххаа
18.03.2008 2:14 ICQ: я понял, что он сделал
18.03.2008 2:14 ICQ: короче, new Foo<Long>(new ArrayList<Long> работает
18.03.2008 2:14 ICQ: new Foo<Long>(new LinkedList<Long> — ошибка компиляции
18.03.2008 2:14 ICQ: поскольку LinkedList не RandomAccess
18.03.2008 2:15 ICQ: но этот чувак, походу, написал new Foo(new LinkedList<Long>
18.03.2008 2:15 ICQ: то есть, просто взял сырую версию класса
18.03.2008 2:15 ICQ: без всяких генериков
18.03.2008 2:15 ICQ: и поэтому там нет вообще никаких проверок
18.03.2008 2:15 Fj: а
18.03.2008 2:15 ICQ: я уже на такое натыкался один раз, это действительно заеб ихней реализации
18.03.2008 2:15 ICQ: но это не имеет отношения к erasure
18.03.2008 2:15 Fj: пиздец. прикольно
18.03.2008 2:16 ICQ: грубо говоря, если ты взял generic-вызов и вызвал его без генериков, от него отрезаются вообще все генерики
18.03.2008 2:16 ICQ: а не только явно прописанные в вызове
18.03.2008 2:16 Fj: так это, а что с порядком перечисления интерфейсов?
18.03.2008 2:16 Fj: это правда, что от него что-то зависит?
18.03.2008 2:16 ICQ: да
18.03.2008 2:17 ICQ: если ты через рефлекшн запросишь этот метод, он будет после erasure уже
18.03.2008 2:17 Fj: жопа
18.03.2008 2:17 ICQ: поэтому будет выглядеть как new Foo(new LinkedList)
18.03.2008 2:17 ICQ: но при этом там можно достать все ограничения, на самом деле
18.03.2008 2:17 ICQ: которые в декларации прописаны
18.03.2008 2:17 ICQ: а не при generic instantiation
18.03.2008 2:17 Fj: можно, я кусок лога туда запощу, потому что там, кажется, не было такого написано?
18.03.2008 2:18 ICQ: ща
18.03.2008 2:18 ICQ: я найду параграф в jls
18.03.2008 2:20 ICQ: хотя там в общем дали ссылку на него
18.03.2008 2:20 ICQ: 4.8 raw types
Скорее всего, в случае автора все разрешение подходящих конструкторов (методов) свелось к raw-типам. Либо он не указал параметр типа при создании объекта (т.е. использовал new RingList вместо new RingList<String>. Либо использовал raw-тип в аргументах (тот же TreeList или LinkedList без указания аргументов, что привело к выбору конструктора (метода) как raw). Если указывать необходимые параметры-типы, то компилятор выдаст ошибку. Кроме того, если не указывать эти типы, то компилятор (sun javac) выдает предупреждение вроде "Note: T.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details". Ну и по спецификации (тот же раздел 4.8): "It is possible that future versions of the Java programming language will disallow the use of raw type".
"It is possible that future versions of the Java programming language will disallow the use of raw type".ага, ну понятно. Просто в .NET этими raw-типами можно пользоваться только для инстанциирования
Джава-компилятор тоже сохраняет параметры и ограничения на типы. Но не плодит на каждую инстанциацию Generic'а отдельный класс. Что, между прочим, позволяет вынести Generic в библиотеку и ее исходный код не потребуется для компиляции. И, кроме того, позволит заменить библиотеку на новую версию совершенно не требуя перекомпиляции всего остального кода. На уровень runtime такие проверки пока не выносили, иначе информация о generic/nongeneric параметрах станет частью типа объекта. Такие проверки на самом деле - хорошо, но не понятно, что делать со всей инфраструктурой, наработанной до версии 1.4 включительно.
Итого мы сейчас имеем то, что имеем. На уровне исходного кода Generics дают некоторую безопасность типов (те же дополнительные проверки, что в список строк не может быть положено число). На уровне байт-кода - дополнительную метаинформацию, которая в дальнейшем используется компилятором и, возможно, при верификации байт-кода (не уверен, если интересно, могу поднять спецификацию JVM и посмотреть, изменился ли процесс верификации). Следующим шагом может быть введение полноценной поддержки о Generic-типа во время выполнения (что может таки сломать совместимость с библиотеками, которые не были generified). Ну а писать на этом не слишком сложно. На этапе разработки компилятор умеет выдавать предупреждения, среды разработки также настраиваются на предупреждение использования raw types, которые уже deprecated. Итого получаются достаточно полноценные (без raw types - абсолютно полноценные) проверки на этапе компиляции. Для runtime иногда возникают сложности, например, когда нужно получить значение параметра-типа. Приходится явно передавать соответствующий объект Class<?>. Но это пока (пока на них не забили) проблемы переходного периода.
Но не плодит на каждую инстанциацию Generic'а отдельный класс. Что, между прочим, позволяет вынести Generic в библиотеку и ее исходный код не потребуется для компиляции. И, кроме того, позволит заменить библиотеку на новую версию совершенно не требуя перекомпиляции всего остального кода.а что возможно какое-то другое поведение?
зы
на всякий случай: generic != template
Почему жава умеет делать подстановку generic'ов в обычные методы, и не умеет в конструкторах?
Вызов Collections.emptyMap(new HashMap<T, V> выдаст Map<T, V>,
а new HashMap(new HashMap<T, V> - просто Map...
class NonGenClassGenCons {
<T> NonGenClassGenCons(T arg) {
}
}
class GenClassNonGenCons<T> {
GenClassNonGenCons(T arg) {
}
}
class GenClassAndCons<T> {
<V> GenClassAndCons(T t, V v) {
}
}
public class Test {
public static void main(String [] args) {
final NonGenClassGenCons e1 = new NonGenClassGenCons("Test");
final GenClassNonGenCons<String> e2 = new GenClassNonGenCons<String>("test");
final GenClassAndCons<String> e3 = new GenClassAndCons<String>("test", "Test");
final GenClassAndCons<String> e4 = new <Object>GenClassAndCons<String>("test", "Test");
}
}
e3 и e4 по сути одно и то же, только e4 записана полностью, а для e3 тип V вычисляется компилятором.
Оставить комментарий
danilov
Странная штука. Хочу создать конструктор по листу с произвольным доступом, пишу:Так она отлично хавает во-первых LinkedList (не RandomAccess а во-вторых TreeList (не generic).
И притом нормально работает.
Более того, если RandomAccess заменить на непустой интерфейс, она нормально работает, если у underlayingList не вызывать методов этого интерфейса.
Иначе вылазит ClassCastException.
Но компилятор всё это отлично хавает.
idea на проверку if(!(underlayingList instanceof RandomAccess выдаёт, что значение по if'ом всегда false.
Этому есть объяснение какое-то или просто багло?
Если заменить на фабрику, то всё становится правильно (компилятор ругается, где надо).