2013-12-23 4 views
11

Интересно, почему этот фрагмент кода успешно компилируется?Ограниченный подстановочный знак не проверен параметром верхнего ограниченного типа

Исходный код:

abstract class A<K extends Number> 
{ 
    public abstract <M> A<? super M> useMe(A<? super M> k); 
} 

Составитель успешно

Как это работает и почему это компилировать? M - это любой тип, так почему его можно использовать ?. Должно ли это быть: <M extends Number>? Это не компилируется:

abstract class A<K extends Number> 
{ 
    public abstract <M> A<? super M> useMe(A<M> k); 
} 

Сообщение об ошибке:

аргумент типа М не в границах переменной K типа, где M, K являются переменными типа: М расширяет объект объявлен в методе useMe (A) K продолжение Номер, указанный в классе A

В чем разница?

+0

Вы можете получить более качественные ответы, включив фактическое сообщение об ошибке, которое вы получаете от компилятора. (Нам не нужно начинать IDE, чтобы понять ваш вопрос.) – meriton

+0

Какое фактическое сообщение об ошибке? Вопрос в том, почему это компилируется? –

+0

Примечание для тех, кто интересуется, заменяя '' '' 'M extends Number>' в более поздней версии, он также позволяет скомпилировать его. – Guvante

ответ

1

Добавление <M extends Number> к первому примеру не добавляет ничего компилятора. Помните, что вы говорите «тип, который является супертипом M», если мы говорим: «M - это подтип числа» и «тип является супертипом M», мы на самом деле не говорим, является ли тип подтипом Число.

Для лучшего примера: M be Integer и переменная типа A<Object>. Хотя очевидно, что это не сработает, оно удовлетворяет всем требованиям функции правильно.

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

+0

Точно, оба разные, так зачем это компилируется? Я знаю смысл символов. – Pawel

+0

@SotiriosDelimanolis: Извините, что вы правы, мой первый ответ не был полным, подумал об этом еще и придумал лучший. – Guvante

2

Это удивительно бессмысленный фрагмент кода.

Все это говорит, что класс A принимает обобщенный тип K, который является Number и есть метод useMe, который возвращает A<T> с некоторым бессмысленным дополнительным ограничением на T (кроме будучи Number очевидно).

Вот реализация, чтобы показать, как мало что говорит по сахару:

abstract class A<K extends Number> { 
    public abstract <M> A<? super M> useMe(A<? super M> k); 
} 

class B extends A<Number> { 

    @Override 
    public <M> A<? super M> useMe(A<? super M> k) { 
     // Not much more you can do here but this. 
     return k; 
    } 

} 

? super M материал является просто бессмысленным gobbledegook - все компилятор может извлечь из него то, что оба параметра передается к нему и результат должен быть суперклассом определенного неназванного класса.

Дженерики существуют, чтобы легко обнаружить ошибки кодирования во время компиляции. Использование mumbo-jumbo, например, это просто вводящая в заблуждение обфускация.

5

Это поведение компилятора обсуждалось на this Eclipse bug. Первоначально компилятор Eclipse делал ошибку для выражения в вашем примере, а javac - нет. Хотя я еще не исследовал JLS напрямую, консенсус, похоже, заключается в том, что в спецификации нет ничего, требующего проверки более низких ограниченных подстановок от ограничений параметров типа.В этой ситуации, в конечном счете, для вызывающего абонента остается присвоить тип, который удовлетворяет ограничениям (как предполагал Стефан Херрманн на этом посту).

+0

вы уверены, что javac не будет! Мои NetBeans также сообщают об этом исключении. – Sage

+0

@Sage Он компилируется для меня в Eclipse (1.7) и javac (sun-jdk 1.7) Ideone: http://ideone.com/lRb23T. Какой компилятор настроен для вашего Netbeans? –

+0

@Sage У меня есть NetBeans 7.4 и первый пример компиляции для меня тоже. JDK 1.7. – Pawel

-1

Есть две части вашего вопроса:

Часть 1: Что такое <M>?

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

Часть 2:

Обобщенные типы должны соответствовать точно. Причина сводится к тому, что если B является подтипом A, SomeClass<T extends B> не является подтипом SomeClass<T extends A>, более конкретно, SomeClass<A> не является подтипом SomeClass<? super A>.

Смежные вопросы