2015-08-25 1 views
9

Создать класс какПроверка типа разбита на совпадение с верхней границей?

public class Play { 
    public static void main(String[] args) throws Exception { 
     outer(Integer.class, inner("abc")); 
    } 

    static <C> void outer(Class<C> c, List<? super C> s){ 
    } 

    static <C> List<C> inner(C c) { 
     return null; 
    } 
} 

и компилирует в Java 8! (Как в Eclipse, 4.5 и JDK1.8_25) https://ideone.com/Q9JLHP

В Eclipse, все оценки выводятся правильно, но как захват outer «s Supplier<? super Integer> когда-либо были удовлетворены аргументом Supplier<String> ??

Редактировать: уточнено, что это Java 8-specific и делает пример менее запутанным.

+0

@ bayou.io Это просто произвольный общий тип, который я выбрал для примера. Я уверен, что компилятор здесь специально не относится. Я обновлю этот пример, чтобы избежать этой путаницы. –

ответ

10

inner("abc") может, по усмотрению компилятора, интерпретироваться как Supplier любого супертипа String. - например,

Supplier<Object> inner = inner("abc"); 

работает просто отлично, потому что "abc"является такжеObject. Вот что происходит здесь: inner возвращает вас Supplier<Object>.

+0

Но это поведение кажется новым для Java 8. Любая ссылка на то, почему это изменение было сделано? Потому что он нарушил проверку типа на 'assertThat()' Hamcrest, который обычно используется. –

+1

Java 8 имеет [вывод целевого типа] (http://openjdk.java.net/jeps/101), который позволяет вводить информацию о выводах типа вниз по AST, а также вверх. Это очень строго необходимо, чтобы заставить лямбды волшебным образом определить правильный тип для своего контекста как общего. –

+2

Помимо помощи лямбда-выражениям, он решает недостатки, существовавшие с момента введения Generics, т. Е. Поскольку вы не могли написать «Список l = Arrays.asList (42);» или «Список l = условие? ...: Collections.emptyList(); 'и т. Д. Если он нарушает существующий код, это существующий код, который является ошибочным, поскольку тот же код прошел бы старый компилятор, когда введенный тип будет вставлен вручную, то есть здесь, говоря« внешний (Integer.class, Play. внутренний («abc»)); ' – Holger

1

Вывод на inner требует, чтобы C является супертипом Integer и String.

Что такое C? Это сложная история. И Integer, и String - Object, конечно. Но оба они тоже Serializable! и Comparable<?> тоже ....

В конце концов, это не имеет большого значения; все, что нам нужно знать, это то, что это «наименьшая верхняя граница» String и Integer, каким бы то ни было образом defined.

+0

' C' не обязательно должен быть супертипом 'Integer' и' String'. Подпись 'List' в' external' просто должна содержать элементы некоторого неопределенного супертипа 'Integer' и' String'. –

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