Por que uma variável “Class” não pode ser passada para instanceof?

89

Por que este código não compila?

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

Por que não posso passar uma variável de classe para instanceof?

eric2323223
fonte

Respostas:

131

O instanceofoperador trabalha em tipos de referência, como Integer, e não em objetos, como new Integer(213). Você provavelmente quer algo como

clazz.isInstance(obj)

Nota lateral: seu código será mais conciso se você escrever

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

Não tenho certeza se você precisa mais de um método, no entanto.

Robert Munteanu
fonte
Sei que o código é totalmente inútil, só quero demonstrar minha confusão :)
eric2323223
6
Integernão é uma classe literal. Integer.classseria um literal de classe (ver § 15.8.2 do JLS: java.sun.com/docs/books/jls/third_edition/html/… ). O instanceofoperador usa um "ReferenceType" (também conhecido como nome de tipo) conforme especificado § 15.20.2 do JLS: java.sun.com/docs/books/jls/third_edition/html/…
Joachim Sauer
3
Eu usaria, clazz.isInstance(obj)pois o objeto já foi fornecido.
Donal Fellows
13

instanceofpode ser usado apenas com nomes de classe explícitos (declarados em tempo de compilação). Para fazer uma verificação de tempo de execução , você deve fazer:

clazz.isInstance(obj)

Isso tem uma pequena vantagem, clazz.isAssignableFrom(..)pois lida obj == nullmelhor com o case .

Eyal Schneider
fonte
5

Como outros mencionaram, você não pode passar uma variável de classe para instanceofporque uma variável de classe faz referência a uma instância de um objeto , enquanto a mão direita de instanceoftem que ser um tipo . Ou seja, instanceofnão significa "y é uma instância do objeto x", significa "y é uma instância do tipo X". Caso você não saiba a diferença entre um objeto e um tipo, considere:

Object o = new Object();

Aqui, o tipo é Objecte oé uma referência à instância do Object com esse tipo. Portanto:

if(o instanceof Object)

é válido mas

if(o instanceof o)

não é porque odo lado direito está um objeto, não um tipo.

Mais específico para o seu caso, uma instância de classe não é um tipo, é um Objeto (que é criado para você pela JVM). Em seu método, Classé um tipo, mas clazzé um objeto (bem, uma referência a um objeto)

O que você precisa é uma maneira de comparar um objeto a um objeto de classe. Acontece que este é popular por isso este é fornecido a você como um método do objeto de classe: isInstance().

Aqui está o Java Doc para isInstance, que explica isso melhor:

public boolean isInstance(Object obj)

Determina se o Object especificado é compatível com a atribuição do objeto representado por esta classe. Este método é o equivalente dinâmico do operador instanceof da linguagem Java. O método retorna true se o argumento Object especificado não for nulo e pode ser convertido para o tipo de referência representado por este objeto Class sem gerar uma ClassCastException. Caso contrário, retorna falso.

Especificamente, se este objeto Class representa uma classe declarada, este método retorna true se o argumento Object especificado for uma instância da classe representada (ou de qualquer uma de suas subclasses); caso contrário, retorna falso. Se este objeto Class representa uma classe de array, este método retorna true se o argumento Object especificado pode ser convertido em um objeto da classe de array por uma conversão de identidade ou por uma conversão de referência de alargamento; caso contrário, retorna falso. Se este objeto Class representa uma interface, este método retorna true se a classe ou qualquer superclasse do argumento Object especificado implementa esta interface; caso contrário, retorna falso. Se este objeto Class representa um tipo primitivo, este método retorna falso.

Parâmetros: obj - o objeto a ser verificado
Retorna: true se obj for uma instância desta classe
Desde: JDK1.1

Rick Hanlon II
fonte
3

Em primeiro lugar, instanceofrequer que o operando à direita seja uma classe real (por exemplo, obj instanceof Objectou obj instanceof Integer) e não uma variável do tipo Class. Em segundo lugar, você cometeu um erro bastante comum de novato que realmente não deveria fazer ... o seguinte padrão:

if ( expressão_condicional ) {
    return true;
} outro{
    retorna falso;
}

O acima pode ser refatorado em:

retornar expressão_condicional ;

Você deve sempre executar essa refatoração, pois ela elimina uma instrução if ... else redundante. Da mesma forma, a expressão é refatorável para o mesmo resultado.return conditional_expression ? true : false;

Michael Aaron Safyan
fonte
2
Isso não é engano. Talvez desajeitado, mas totalmente bem. Talvez você queira um código adicional antes de retornar em um futuro próximo ...
O incrível janeiro