Почему «t instanceof T» не допускается, когда T является параметром типа, а t является переменной? - PullRequest
6 голосов
/ 05 января 2012

Eclipse говорит, что операция instanceof недопустима с параметром типа из-за универсального ластика типа.

Я согласен, что во время выполнения информация о типе не сохраняется.Но рассмотрим следующее обобщенное объявление класса:

class SomeClass<T>{
    T t;
    SomeClass(Object o){
        System.out.println(o instanceof T);   // Illegal
    }   
}        

Во время выполнения T не будет присутствовать!Но если я создаю экземпляр этого класса типа Integer, то соответствующий объект будет иметь поле t типа Integer.

Тогда, почему я не могу проверить тип переменной с T, который можно заменить на Integer?во время выполнения.И я бы на самом деле делал что-то вроде «o instanceof Integer».

В каких случаях разрешение instanceof с параметром типа может вызвать проблемы, так что это запрещено?

Ответы [ 7 ]

5 голосов
/ 05 января 2012

Но если я создам экземпляр этого класса типа Integer, то соответствующий объект будет иметь поле t типа Integer

Нет, не будет.У него будет поле типа Object.Просто каждый раз, когда вы получаете к нему доступ, он будет приведен к целому числу.

Рассмотрим следующий код:

SomeClass<Integer> c = new SomeClass<Integer>();
SomeClass untyped = (SomeClass)c; // Which type was it?
SomeClass<String> stringTyped = (SomeClass<String>)untyped; // Now it's STRING??

Работает.Дает вам кучу предупреждений компилятора, но работает.Потому что поле T на самом деле имеет тип Object и может быть приведено к чему угодно.

5 голосов
/ 05 января 2012

Если вам нужен T во время выполнения, вам нужно предоставить его во время выполнения.Это часто делается передачей класса , который должен быть T.

class SomeClass<T> {
    final T t;

    public SomeClass(Class<T> tClass, T t) {
        if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass);
        this.t = t;
    }

    private SomeClass(T t) {
        this.t = t;
    }

    public static <T> SomeClass<T> of(Class<T> tClass, T t) {
        if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass);
        return new SomeClass(t);
    }
} 

// doesn't compile
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, "one");

Class clazz = Integer.class;
// compiles with a warning and throws an IAE at runtime.
SomeClass<Integer> intSomeClass = (SomeClass<Integer>) SomeClass.of(clazz, "one");

// compiles and runs ok.
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, 1);
3 голосов
/ 05 января 2012

После компиляции оператора o instanceof T будет o instanceof Object, и поскольку все типы являются производными от Object, он всегда будет иметь значение true.Разрешение такого рода тестов дало бы ложноположительные результаты

2 голосов
/ 05 января 2012

Из-за стирания типа это никогда не работает. Во время выполнения вы знаете только, что у вашего класса есть параметр типа T, но не знаете, какой это тип для данного экземпляра. Поэтому вы не можете определить, имеет ли объект тип T для начала, потому что вы не знаете, что такое T, а не потому, что это вызовет какие-то проблемы.

Если вам нужно выполнить такую ​​проверку во время выполнения, передайте токен типа в ваш объект явно:

SomeClass(Object o, Class<T> type) {
    System.out.println(type.isInstance(o));
}
1 голос
/ 05 января 2012

Но если я создам экземпляр этого класса типа Integer, то соответствующий объект будет иметь поле t типа Integer.

На самом деле это не так.Было бы поле t типа Object.Как вы сказали, дженерики - это почти полностью синтаксический сахар (за исключением того, что когда вы расширяете дженерик-класс и указываете параметр типа, тип остается метаданными в файле класса).

0 голосов
/ 09 октября 2016

Java реализует свои Обобщения, используя «Erasure», она может проверить тип и удалить информацию о параметре типа в « COMPILE TIME », в « RUN TIME » будет только ГРАНИЦЫ параметров типа, так что не будет ничего вроде "Integer"

0 голосов
/ 05 января 2012

Аргументы универсального типа не известны во время выполнения, поэтому нет класса, с которым можно было бы сравнивать.T известен только во время компиляции.Дженерики только помогают разработчику писать код проще.Но во время выполнения аргументы являются просто Object экземплярами.

...