2013-12-12 3 views
11

я получаю следующее сообщение: сборникнесовместимые типы и свежий тип переменной

[javac] ... error: incompatible types 
[javac]   exceptionClassHolder = new Holder<>((new Exception()).getClass()); 
[javac]        ^
[javac] required: Holder<Class<? extends Exception>> 
[javac] found: Holder<Class<CAP#1>> 
[javac] where CAP#1 is a fresh type-variable: 
[javac]  CAP#1 extends Exception from capture of ? extends Exception 
[javac] 1 error 

Казалось бы мне, что согласно сообщению все должно быть правильно. CAP#1 действительно расширяет исключение. Итак, как должно быть понято это сообщение? SSCCE ниже (первоначально не писал, так как я надеялся понять сообщение об ошибке непосредственно в общем случае):

class Holder<T> { 
    public T t; 
    public Holder(T t) { 
     this.t = t; 
    } 
} 

public class FooMain { 
    public static void main(String args[]) throws Exception { 
     Holder<Class<? extends Exception>> exceptionClassHolder; 
     exceptionClassHolder = new Holder<>((new Exception()).getClass()); 
    } 
} 
+2

Покажите нам код – Bohemian

+1

@Bohemian OK Постараюсь воспроизвести первый в более минимальной ситуации –

ответ

17

К сожалению, существующие ответы не объясняют, что здесь происходит. Во-первых, решение просто указать тип аргумента Holder:

Holder<Class<? extends Exception>> exceptionClassHolder; 
exceptionClassHolder = 
     new Holder<Class<? extends Exception>>(new Exception().getClass()); 

Причина ваша версия не работает, потому что new Exception().getClass() возвращает Class<? extends Exception>, где ? является wildcard capture (упоминаемый в сообщении об ошибке компилятора как CAP#1). Поскольку вы используете «алмазный оператор» с new Holder<>, компилятор сообщает Class<CAP#1 extends Exception> для T и поэтому Holder<Class<CAP#1 extends Exception>> - тип созданного объекта.

Однако это не соответствует заявленному типу Holder<Class<? extends Exception>>. Он использует nested wildcard, который не захватывает: в то время как CAP#1 extends Exception является некоторые конкретный тип расширения Exception, вложенная ? extends Exception представляет буквально любого типа расширения Exception.

И в то время как Class<CAP#1 extends Exception> является подтипом Class<? extends Exception>, Holder<Class<CAP#1 extends Exception>> не является подтипом Holder<Class<? extends Exception>> потому generics aren't covariant, поэтому задание не выполняется.

С помощью ссылки Class<? extends Exception> на номер T вы помогаете компилятору избежать этой «ловушки».

Смотрите мои похожие ответы на эти посты:

+0

+1 для расширенного объяснения. Но я не понимаю, почему вы заявляете, что «во-первых, решение состоит в том, чтобы просто указать аргумент типа для Holder». Зачем? В Java 7 это должно быть выведено компилятором. В любом случае, если нет, он должен был разбиться во время компиляции, что не является проблемой OP. –

+1

Он выведен компилятором, но не «правильно» - вывод дает преимущество аргументу конструктора над переменной. И это не сработало во время компиляции. –

+0

Интересно. Я только посмотрел на возвращаемый тип Object.getClass(), а не на текст документации, который действительно говорит, что фактический тип, возвращаемый, является 'Class '. Правильно ли я считаю, что это особый случай, который обрабатывается специально компилятором, и что невозможно сделать то, что getClass() делает с обычным кодом Java? –

2
Holder<? extends Class<? extends Exception>> exceptionClassHolder; 
    exceptionClassHolder = new Holder<>((new Exception()).getClass()); 

Причина заключается в том, что

  1. Поскольку вы не используете Exception.class но Объект исключения, java считает, что требуется ? extends Exception.
  2. То же самое относится к getClass(), еще ? extends Class необходимо, хотя класс является окончательным.

Конечно, однажды это будет упрощено.

+0

Это не нужно - см. Мой ответ. –

+1

@PaulBellora мое решение работает _with_ алмазным оператором (как опрошено). Читая ваш отличный ответ (мой +1), создается впечатление, что алмазный оператор не должен работать._ Как вам кажется, у меня есть язык программирования/компилятора, так что вы можете немного активировать немного. Спасибо. –

+0

Вы правы, что алмазный оператор работает при назначении 'Holder > '- это потому, что этот тип назначается из' Holder > ', в отличие от' Holder > '. Процесс вывода типа остается прежним - компилятор дает приоритет аргументу конструктора и указывает 'Class ' для 'T'. –

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