Java generics компилируется в Eclipse, но не в javac

Мне пришлось обнаружить, что у меня есть Java-код в моем проекте, который компилируется и работает отлично в Eclipse, но генерирует ошибку компиляции в javac.

Автономный фрагмент:

import java.util.HashSet;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
    Set<Integer> setOfInts = new HashSet<Integer>();
    Set<Object> setOfObjects = covariantSet(setOfInts);
    }

    public static <S, T extends S> Set<S> covariantSet(Set<T> set) {
    return new HashSet<S>(set);
    }

}

Компиляция в javac возвращается:

Main.java:10: incompatible types
found   : java.util.Set<java.lang.Integer>
required: java.util.Set<java.lang.Object>
    Set<Object> setOfObjects = covariantSet(setOfInts);
                                           ^

Эта ошибка теперь предотвращает создание проекта в Maven. Поскольку компилятор Eclipse построен с большей толерантностью, теперь я должен принять определение и использование фрагментов, как указано выше, статический метод не является допустимым Java?

Ответ 1

Кажется, что Sun 1.6 JDK не может вывести правильный тип. На моей машине работает следующее:

Set<Object> setOfObjects = Main.<Object, Integer>covariantSet(setOfInts);

Обратите внимание, что вы должны вызывать статический метод с префиксом имени класса

Ответ 2

Вы правы. Эта проблема действительно существует. Eclipse не использует javac. Он использует свой собственный компилятор.

На самом деле javac является "правильным". Дженерики - это стирания. Тип S не включен в ваш байт-код, поэтому jvm не имеет достаточной информации о типе возвращаемого значения во время выполнения. Чтобы решить проблему, измените прототип метода следующим образом:

public static <S, T extends S> Set<S> covariantSet(Set<T> set, Class<S> returnType)

Теперь возвращаемый тип передается методу во время выполнения, а компилятор не должен жаловаться.

Ответ 3

В сводке сборки Maven вы установили версию компилятора.

В Ant он выглядит следующим образом:

<property name="source.version" value="1.5" />

найдите 1.3 или 1.4 или скомпилируйте, чтобы найти это значение в maven skripts

Со значением 1.5 компилятор будет принимать генерические файлы (см. ваши сообщения об ошибках)

Ответ 4

Я знаю этот старый вопрос, но хочу отметить, что функция может быть записана как:

import java.util.HashSet;
import java.util.Set;

public class Main {

public static void main(String[] args) {
        Set<Integer> setOfInts = new HashSet<Integer>();
        Set<Object> setOfObjects = covariantSet(setOfInts);
    }

    public static <S> Set<S> covariantSet(Set<? extends S> set) {
        return new HashSet<S>(set);
    }

}

Это немного чище, и вы можете использовать эту функцию точно так, как вы намеревались (с неявным типичным типированием).

Ответ 5

Добавьте следующий плагин к вашему pom.xml:

<plugin>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>2.3.2</version>
     <configuration>
          <source>1.6</source>
          <target>1.6</target>
     </configuration>
</plugin>