Универсальные введенные внутренние классы в Java

Я учился и экспериментировал с Дженериками Java некоторое время, но я столкнулся с чем-то, что я не могу объяснить. Возьмите, например, следующий код:

public class Question {
    public <T> Sub<T> getSub(Class<T> c) {
        return new Sub<T>(c);
    }
    public class Sub<S> {
        private Class<S> c;
        public Sub(Class<S> c) {
            this.c = c;
        }
        public void add(S s) {
        }
    }
}

И тестовый код:

import generics.Question.Sub;

public class Answer {
    public static void main(String [] args) {
        Question q = new Question();
        Sub<String> s = q.getSub(String.class);
        s.add("");
    }
}

Когда это выполняется, это дает замечательно загадочное сообщение об ошибке:

C:\Answer.java:8: incompatible types
found   : generics.Question.Sub<java.lang.String>
required: generics.Question.Sub<java.lang.String>
        Sub<String> s = q.getSub(String.class);
1 error

Теперь, посредством некоторого экспериментирования я разработал, как предотвратить ошибку компилятора. Я могу или заставить Sub классифицировать статический внутренний класс, или я должен назвать класс Sub Вопросом. Sub <Строка>. То, что я не могу сделать, объясняют, почему я должен сделать это.

Я сделал некоторое чтение документации Java относительно Дженериков, но ни один не покрывает этот конкретный случай.

Кто-либо может объяснить, почему код является несовместимым типом в своей текущей форме?

Править-

Рассмотрение этого ближе, я вижу, что получаю то же поведение за пределами Netbeans. Если у меня есть код в следующей структуре:

generics\
generics\Question.java
generics\Answer.java

Когда я компилирую файлы вместе, я не получаю ошибку:

C:\>javac generics\Question.java generics\Answer.java

C:\>

Однако, когда я компилирую Вопрос сначала и затем Ответ, я получаю ошибку:

C:\>javac generics\Question.java

C:\>javac generics\Answer.java
generics\Answer.java:8: incompatible types
found   : generics.Question.Sub<java.lang.String>
required: generics.Question.Sub<java.lang.String>
        Sub<String> s = q.getSub(String.class);
                                ^
1 error

Я услышал что-то упомянутое о Стирании Типа. Имеет место это в этой ситуации?

15
задан gencoreoperative 3 March 2010 в 10:08
поделиться

1 ответ

Стирание типов - это свойство способа, которым универсальные шаблоны в настоящее время реализованы в Java. Это означает, что тип переменных известен только во время компиляции, но не во время выполнения. Так, например, в следующем:

Map<String,String> map = new HashMap<String,String>();

компилятор знает, что нужно проверять элементы, помещаемые на основе String / String. Однако скомпилированный код ничего не знает о String, String - вы все равно можете вставлять объекты с неправильным типом, например:

Map other = (Map)map;
other.put(new Integer(3), new Double( 4.5 );

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

Я сомневаюсь, что стирание типов здесь является проблемой - поскольку во время компиляции у вас есть полная информация о типах - скорее, это, вероятно, ошибка. Существует довольно много проблем с дженериками (из реализации), и существуют разные компиляторы, используемые с JavaC и Eclipse, поэтому могут быть обнаружены разные ошибки. В некоторых случаях компилятор Eclipse был более верен спецификации, чем компилятор Sun (поэтому Eclipse создает ошибки, а Sun - нет), и это в основном из-за сложности способа работы системы типов.

Так что, скорее всего, это одна (или несколько) ошибок с универсальными шаблонами в компиляторе 1.5.0_14 ...

1
ответ дан 1 December 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: