¿Por qué no se puede pasar una variable "Clase" a instanceof?

89

¿Por qué no se compila este código?

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

¿Por qué no puedo pasar una variable de clase a instanceof?

eric2323223
fuente

Respuestas:

131

El instanceofoperador trabaja con tipos de referencia, como Integer, y no con objetos, como new Integer(213). Probablemente quieras algo como

clazz.isInstance(obj)

Nota al margen: su código será más conciso si escribe

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

Sin embargo, no estoy realmente seguro de si necesita un método.

Robert Munteanu
fuente
Sé que el código es totalmente inútil, solo quiero demostrar mi confusión :)
eric2323223
6
Integerno es un literal de clase. Integer.classsería un literal de clase (ver § 15.8.2 de JLS: java.sun.com/docs/books/jls/third_edition/html/… ). El instanceofoperador toma un "ReferenceType" (también conocido como un nombre de tipo) como se especifica en § 15.20.2 de JLS: java.sun.com/docs/books/jls/third_edition/html/…
Joachim Sauer
3
Lo usaría clazz.isInstance(obj)ya que el objeto ya se ha proporcionado.
Donal Fellows
13

instanceofsolo se puede usar con nombres de clase explícitos (indicados en el momento de la compilación). Para realizar una verificación de tiempo de ejecución , debe hacer:

clazz.isInstance(obj)

Esto tiene una pequeña ventaja, clazz.isAssignableFrom(..)ya que se ocupa obj == nullmejor del caso .

Eyal Schneider
fuente
5

Como han mencionado otros, no puede pasar una variable de clase a instanceofporque una variable de clase hace referencia a una instancia de un Objeto , mientras que la mano derecha de instanceoftiene que ser un tipo . Es decir, instanceofno significa "y es una instancia del Objeto x", significa "y es una instancia del tipo X". En caso de que no sepa la diferencia entre un objeto y un tipo, considere:

Object o = new Object();

Aquí, el tipo es Object, y oes una referencia a la instancia del Objeto con ese tipo. Así:

if(o instanceof Object)

es válido pero

if(o instanceof o)

no es porque oen el lado derecho hay un Objeto, no un tipo.

Más específico para su caso, una instancia de clase no es un tipo, es un Objeto (que la JVM crea para usted). En su método, Classes un tipo, pero clazzes un Objeto (bueno, una referencia a un Objeto)

Lo que necesita es una forma de comparar un objeto con un objeto de clase. Resulta que este es muy popular por lo que este se le proporciona como un método de la clase de objeto: isInstance().

Aquí está el Java Doc para isInstance, que explica esto mejor:

public boolean isInstance(Object obj)

Determina si el objeto especificado es compatible con la asignación del objeto representado por esta clase. Este método es el equivalente dinámico del operador instanceof del lenguaje Java. El método devuelve verdadero si el argumento Object especificado no es nulo y se puede convertir al tipo de referencia representado por este objeto Class sin generar una ClassCastException. Devuelve falso de lo contrario.

Específicamente, si este objeto Clase representa una clase declarada, este método devuelve verdadero si el argumento Objeto especificado es una instancia de la clase representada (o de cualquiera de sus subclases); devuelve falso en caso contrario. Si este objeto Class representa una clase de matriz, este método devuelve verdadero si el argumento Object especificado se puede convertir en un objeto de la clase de matriz mediante una conversión de identidad o una conversión de referencia de ampliación; devuelve falso en caso contrario. Si este objeto Clase representa una interfaz, este método devuelve verdadero si la clase o cualquier superclase del argumento Objeto especificado implementa esta interfaz; devuelve falso en caso contrario. Si este objeto Class representa un tipo primitivo, este método devuelve falso.

Parámetros: obj - el objeto a verificar
Devuelve: verdadero si obj es una instancia de esta clase
Desde: JDK1.1

Rick Hanlon II
fuente
3

En primer lugar, instanceofrequiere que el operando de la derecha sea una clase real (por ejemplo, obj instanceof Objecto obj instanceof Integer) y no una variable de tipo Class. En segundo lugar, ha cometido un error de novato bastante común que realmente no debería hacer ... el siguiente patrón:

if ( conditional_expression ) {
    devuelve verdadero;
} más {
    falso retorno;
}

Lo anterior se puede refactorizar en:

return conditional_expression ;

Siempre debe realizar esa refactorización, ya que elimina una instrucción if ... else redundante. De manera similar, la expresión se puede refactorizar al mismo resultado.return conditional_expression ? true : false;

Michael Aaron Safyan
fuente
2
Eso no es un error. Quizás torpe pero totalmente bien. Tal vez desee un código adicional antes de regresar en el futuro previsible ...
El increíble