¿Cómo determinar la clase de un objeto?

510

Si clase By clase Cextienden clase Ay tengo un objeto de tipo Bo C, ¿cómo puedo determinar de qué tipo es una instancia?

portador
fuente
14
@starblue Casting sería lo primero que me viene a la mente. Dudo que el operador de instancia de existiría si no fuera necesario.
b1nary.atr0phy
@ b1nary.atr0phy, ¿no sería bueno utilizar primero el operador isntanceof? Si hay un elenco a un tipo incompatible, creo que eso dará como resultado una ClassCastException
committedandroider

Respuestas:

801
if (obj instanceof C) {
//your code
}
Adaptador IA
fuente
31
Es útil observar la verificación inversa o cómo verificar si un Objeto NO es una instancia de una clase:if(!(obj instanceof C))
Dzhuneyt
32
Creo que el método getClass () es la respuesta a la pregunta original. En este caso (obj instanceof A) también daría una salida "verdadera", pero la intención es encontrar la clase de tiempo de ejecución del objeto en la imagen. Si Parent1 y Child2 amplían Parent1, intente lo siguiente code Child1 child1 = new Child1 (); Parent1 parentChild = new Child2 (); Child2 child2 = new Child2 (); (instancia child1 de Parent1); (child1 instanceof Child1); (parentChild instanceof Child2); (parentChild instanceof Parent1); (parentChild instanceof Child1); code , puede borrar la intención de instancia de.
Bhavesh Agarwal
Definitivamente una alternativa a la construcción de una interfaz
JohnMerlino
3
¿Qué sucede si tengo dos clases que implementan una interfaz única? ¿Cómo distingo la clase exacta del objeto?
olyv
3
Sin embargo, una cosa no funciona si obj es nulo. La solución sería ParentInterface.class.isAssignableFrom (Child.class)
alexbt
351

Use Object.getClass () . Devuelve el tipo de tiempo de ejecución del objeto.

Bill el lagarto
fuente
12
Así es como se determina la clase de un objeto
AA_PV
@ Bill respuesta impecable
Gaurav
1
No estoy seguro de por qué esta no es la respuesta más popular
eicksl
178

Se presentaron múltiples respuestas correctas, pero todavía hay más métodos: Class.isAssignableFrom()y simplemente intentar lanzar el objeto (que podría arrojar un ClassCastException).

Posibles formas resumidas

Resumamos las posibles formas de probar si un objeto objes una instancia de tipo C:

// Method #1
if (obj instanceof C)
    ;

// Method #2
if (C.class.isInstance(obj))
    ;

// Method #3
if (C.class.isAssignableFrom(obj.getClass()))
    ;

// Method #4
try {
    C c = (C) obj;
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

// Method #5
try {
    C c = C.class.cast(obj);
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

Diferencias en el nullmanejo

Sin nullembargo, hay una diferencia en el manejo:

  • En los primeros 2 métodos, las expresiones evalúan falsesi objes null( nullno es una instancia de nada).
  • El tercer método arrojaría un NullPointerExceptionobviamente.
  • Los métodos 4 y 5, por el contrario, aceptan nullporque nullse pueden lanzar a cualquier tipo.

Para recordar: null no es una instancia de ningún tipo, pero se puede convertir a cualquier tipo.

Notas

  • Class.getName()no debe usarse para realizar una prueba "es-instancia-de" porque si el objeto no es de tipo Csino una subclase de él, puede tener un nombre y un paquete completamente diferentes (por lo tanto, los nombres de clase obviamente no coincidirán) pero es Todavía de tipo C.
  • Por la misma razón de herencia Class.isAssignableFrom()no es simétrica :
    obj.getClass().isAssignableFrom(C.class)regresaría falsesi el tipo de objes una subclase de C.
icza
fuente
66
Este es un gran resumen de muchas de las dificultades en los diferentes métodos. ¡Gracias por una redacción tan completa!
Kelsin
32

Puedes usar:

Object instance = new SomeClass();
instance.getClass().getName(); //will return the name (as String) (== "SomeClass")
instance.getClass(); //will return the SomeClass' Class object

HTH Pero creo que la mayoría de las veces no es una buena práctica usar eso para controlar el flujo o algo similar ...

Johannes Weiss
fuente
Lo usé para crear un registrador genérico, así que envié un objeto al registrador, y se registra dependiendo del nombre de la clase del objeto, en lugar de dar una etiqueta de registro o una cadena de registro cada vez. gracias
MBH
24

Cualquier uso de cualquiera de los métodos sugeridos se considera un olor a código que se basa en un mal diseño de OO.

Si su diseño es bueno, no debería necesitar usar getClass()o instanceof.

Cualquiera de los métodos sugeridos servirá, pero es algo a tener en cuenta, en cuanto al diseño.

Yuval Adam
fuente
3
Sí, probablemente el 99% de los usos de getClass e instanceof se pueden evitar con llamadas a métodos polimórficos.
Bill the Lizard
3
estoy de acuerdo. en este caso, estoy trabajando con objetos generados a partir de xml siguiendo un esquema mal diseñado del que no soy propietario.
transportista
28
No nessecarily. A veces la separación de las interfaces es buena. Hay momentos en los que desea saber si A es un B, pero no desea hacer obligatorio que A sea un B, ya que solo se requiere A para la mayoría de las funciones: B tiene una funcionalidad opcional.
MetroidFan2002
8
Además, hay momentos en los que necesita asegurarse de que el objeto sea de la misma clase con la que se está comparando; Por ejemplo, me gusta anular el método de igualdad de objetos cuando creo mi propia clase. Siempre verifico que el objeto que entra es de la misma clase.
StackOverflowed
58
Además, diría que decirle a la gente algo malo sin explicar exactamente por qué o dar una referencia a un documento, libro o cualquier otro recurso en el que se explique el problema no se considera constructivo. Por lo tanto, y sabiendo que estoy en StackOverflow, no sé por qué la gente ha votado tanto por esta respuesta. Algo está cambiando aquí ...
Adrián Pérez
15

Podemos usar la reflexión en este caso

objectName.getClass().getName();

Ejemplo:-

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String name = request.getClass().getName();
}

En este caso, obtendrá el nombre de la clase que el objeto pasa a la HttpServletRequestvariable de referencia de la interfaz.

usuario1884500
fuente
esto es correcto. usar solo obj.getClass()devolverá el className, prefixex por la palabraclass
x6iae
request.getClass().getName();imprime todo el paquete! junto con el nombre de la clase
shareef
13

También hay un .isInstancemétodo en la Classclase " ". si obtiene la clase de un objeto a través de myBanana.getClass(), puede ver si su objeto myApplees una instancia de la misma clase que a myBananatravés de

myBanana.getClass().isInstance(myApple)
Andreas Petersson
fuente
1

consultar con isinstance()no sería suficiente si quieres saber en tiempo de ejecución. utilizar:

if(someObject.getClass().equals(C.class){
    // do something
}
Alon Gouldman
fuente
0

Uso la función de soplado en mi clase GeneralUtils, verifique que puede ser útil

    public String getFieldType(Object o) {
    if (o == null) {
        return "Unable to identify the class name";
    }
    return o.getClass().getName();
}
Ahmed Salem
fuente
0

Usé genéricos de Java 8 para obtener cuál es la instancia del objeto en tiempo de ejecución en lugar de tener que usar la caja del interruptor

 public <T> void print(T data) {
    System.out.println(data.getClass().getName()+" => The data is " + data);
}

pase cualquier tipo de datos y el método imprimirá el tipo de datos que pasó mientras lo llamaba. p.ej

    String str = "Hello World";
    int number = 10;
    double decimal = 10.0;
    float f = 10F;
    long l = 10L;
    List list = new ArrayList();
    print(str);
    print(number);
    print(decimal);
    print(f);
    print(l);
    print(list);

Siguiente es la salida

java.lang.String => The data is Hello World
java.lang.Integer => The data is 10
java.lang.Double => The data is 10.0
java.lang.Float => The data is 10.0
java.lang.Long => The data is 10
java.util.ArrayList => The data is []
Saurabh Verma
fuente