Подтвердить что ты не робот

Msgstr "Установить <? Extends Class <? Extends Throwable >>" на самом деле?

Я использую небольшой общий метод для создания наборов из vararg элементов, например

public <T> Set<T> createSet( T... elements ) { ...

В последнее время, однако, я столкнулся с ситуацией, когда компилятор не делал того, что я ожидал от него. Из следующего createSet() использует только s3 работает.

Set<Class<? extends Throwable>> s1 = createSet( Exception.class, RuntimeException.class );

Set<? extends Class<Throwable>> s2 = createSet( Exception.class, RuntimeException.class );

Set<? extends Class<? extends Throwable>> s3 = createSet( Exception.class, RuntimeException.class );

Может ли кто-нибудь дать ясное объяснение того, почему s3 работает и что может быть неправильным с моим мнением о s1 - что было моим первоначальным кодированием? Спасибо.

4b9b3361

Ответ 1

Проблема заключается просто в логике вывода. s1 работает просто отлично (ну, кроме предупреждений vararg), если вы явно введите вызов метода:

Set<Class<? extends Throwable>> s1 = 
    this.<Class<? extends Throwable>>createSet( Exception.class, RuntimeException.class );

Но по умолчанию возвращаемый тип, заданный вашими параметрами, равен Set<Class<? extends Exception>> (я полагаю, потому что это самая конкретная возможность). Вам просто нужно дать компилятору подсказку здесь, так как без него это по существу пытается сделать это:

Set<Class<? extends Exception>> temp = createSet(Exception.class, RuntimeException.class);
Set<Class<? extends Throwable>> s1 = temp;

Что не допускается, поскольку с точки зрения компилятора вы можете поместить a OutOfMemoryError.class в temp, который нарушит его тип.

Изменить

Причина s3 работает для вас, потому что Class<? extends Exception> можно присваивать Class<? extends Throwable>:

//this works
Class<? extends Exception> exceptionRef = Exception.class;
Class<? extends Throwable> throwableRef = exceptionRef;

и поэтому ключевое слово extends предоставляет вам возможность конвертировать из Set<Class<? extends Exception>> в Set<? extends Class<? extends Throwable>>:

//this works too
Set<Class<? extends Exception>> exceptionSetRef = ...;
Set<? extends Class<? extends Throwable>> throwableSetRef = exceptionSetRef;

К сожалению, это, вероятно, не то, что вы хотите, с этого момента вы не можете поместить ничего в throwableSetRef.

Ответ 2

Я думаю, потому что ближайший общий тип Exception и RuntimeException - это Исключение, а не Throwable. T в invokeation createSet() вызывается как Class<? extends Exception>, и это незаконно назначать Set<Class<? extends Exception>> переменной типа Set<Class<? extends Throwable>

Это работает:

Set<Class<? extends Exception>> s1 = createSet( Exception.class, RuntimeException.class );

Ответ 3

Чтобы сделать возможные проблемы s1 и s2 более понятными, замените Class<T> на List<T>.

Тогда:

List<RuntimeException> runtimeExceptions = new ArrayList<RuntimeException>();

Set<List<RuntimeException>> listsOfRuntimeExceptions =
    new HashSet<Lis<RuntimeException>>();
listsOfRuntimeExceptions.add(runtimeExceptions);

Set<? extends List<? extends Throwable>> listsOfThrowables = 
    listsOfRuntimeExceptions; // This is legal 

Set<List<? extends Throwable>> s1 = listsOfThrowables; // Imagine that this is legal
s1.add(Arrays.asList(new Exception())); // Type safety of listsOfRuntimeExceptions is violated

Set<? extends List<Throwable>> s2 = listsOfThrowables; // Imagine that this is legal
s2.get(0).add(new Exception()); // Type safety of runtimeExceptions is violated

Ответ 4

Я думаю, проблема здесь связана с тем, как компилятор определяет "верхнюю границу" (в терминах "Типы" ) для ваших варгаров. Если мы проверим http://download.oracle.com/javase/tutorial/java/generics/non-reifiable-varargs-type.html, мы увидим, что для s1 верхняя граница, которую вы получаете, равна Class<? extends Exception> (и предупреждение который генерируется). Ошибка в том, что в конце вы пытаетесь преобразовать Set<Class<? extends Exception>> в Set<Class<? extends Throwable>>. Если вы переписываете s1 на:

Set<Class<? extends Throwable>> s1 = createSet( Exception.class, RuntimeException.class, Throwable.class);

тогда верхний граничный тип Set<Class<? extends Throwable>>, снова генерирующий предупреждение, но без ошибок.