Почему в instanceof нельзя передать переменную «Class»?

89

Почему этот код не компилируется?

    public boolean isOf(Class clazz, Object obj){
        if(obj instanceof clazz){
            return true;
        }else{
            return false;
        }
    }

Почему я не могу передать переменную класса instanceof?

eric2323223
источник

Ответы:

131

instanceofОператор работает на ссылочных типов, как Integer, а не на объекты, как new Integer(213). Вы, наверное, хотите что-то вроде

clazz.isInstance(obj)

Примечание: ваш код будет более лаконичным, если вы напишете

public boolean isOf(Class clazz, Object obj){
    return clazz.isInstance(obj)
}

Не совсем уверен, нужен ли вам метод больше.

Роберт Мунтяну
источник
Я знаю, что этот код совершенно бесполезен, я просто хочу продемонстрировать свое замешательство :)
eric2323223, 07
6
Integerэто не литерал класса. Integer.classбудет литералом класса (см. § 15.8.2 JLS: java.sun.com/docs/books/jls/third_edition/html/… ). instanceofОператор принимает «ReferenceType» (он же имя типа) , как указано § 15.20.2 из JLS: java.sun.com/docs/books/jls/third_edition/html/...
Joachim Sauer
3
Я бы использовал, clazz.isInstance(obj)поскольку объект уже поставлен.
Donal Fellows
13

instanceofможет использоваться только с явными именами классов (указанными во время компиляции). Чтобы выполнить проверку во время выполнения , вы должны сделать:

clazz.isInstance(obj)

У этого есть небольшое преимущество, clazz.isAssignableFrom(..)так как он obj == nullлучше подходит для случая .

Эяль Шнайдер
источник
5

Как уже упоминалось, вы не можете передать переменную класса, instanceofпотому что переменная класса ссылается на экземпляр объекта , а правая сторона instanceofдолжна быть типом . То есть instanceofне означает «y является экземпляром объекта x», это означает «y является экземпляром типа X». Если вы не знаете разницы между объектом и типом, подумайте:

Object o = new Object();

Здесь, тип Objectи oявляется ссылкой на экземпляр объекта с этим типом. Таким образом:

if(o instanceof Object)

действительно, но

if(o instanceof o)

не потому, oчто справа находится объект, а не тип.

Более конкретно для вашего случая, экземпляр класса - это не тип, это объект (который создается для вас JVM). В вашем методе Classэто тип, но clazzэто объект (ну, ссылка на объект)

Что вам нужно, так это способ сравнить объект с объектом класса. Оказывается, что это популярное , так это предоставляется вам в качестве метода объекта класса: isInstance().

Вот документ Java для isInstance, который лучше объясняет это:

public boolean isInstance(Object obj)

Определяет, является ли указанный объект совместимым по назначению с объектом, представленным этим классом. Этот метод является динамическим эквивалентом оператора instanceof языка Java. Метод возвращает истину, если указанный аргумент Object не равен нулю и может быть приведен к ссылочному типу, представленному этим объектом Class, без создания ClassCastException. В противном случае возвращается false.

В частности, если этот объект Class представляет объявленный класс, этот метод возвращает значение true, если указанный аргумент Object является экземпляром представленного класса (или любого из его подклассов); в противном случае возвращается false. Если этот объект Class представляет класс массива, этот метод возвращает истину, если указанный аргумент Object может быть преобразован в объект класса массива путем преобразования идентичности или преобразования расширяющейся ссылки; в противном случае возвращается false. Если этот объект Class представляет интерфейс, этот метод возвращает true, если класс или любой суперкласс указанного аргумента Object реализует этот интерфейс; в противном случае возвращается false. Если этот объект Class представляет примитивный тип, этот метод возвращает false.

Параметры: obj - объект для проверки.
Возвращает: true, если obj является экземпляром этого класса.
Поскольку: JDK1.1

Рик Хэнлон II
источник
3

Во-первых, instanceofтребуется, чтобы операнд справа был фактическим классом (например, obj instanceof Objectили obj instanceof Integer), а не переменной типа Class. Во-вторых, вы сделали довольно частую ошибку новичков, которую действительно не следует делать ... следующий шаблон:

if ( conditional_expression ) {
    вернуть истину;
} else {
    вернуть ложь;
}

Вышесказанное можно преобразовать в:

возврат условного_выражения ;

Вы должны всегда выполнять этот рефакторинг, поскольку он устраняет избыточный оператор if ... else. Точно так же выражение можно отредактировать для получения того же результата.return conditional_expression ? true : false;

Михаил Аарон Сафян
источник
2
Это не ошибка. Может быть, неуклюже, но все в порядке. Может быть, вам понадобится дополнительный код, прежде чем вернуться в обозримом будущем ...
Невероятное