2009-01-26 14 views
8

Actualmente poseo una lista de objetos (usando Java 1.3), y digamos que quería lanzar uno de los objetos devueltos de list.get (i) a un tipo del cual solo conozco el nombre de la Clase como una Cadena. Esencialmente, ¿cómo hago I Objeto o = (nombre de clase) list.get (i); donde className es una variable String de un className.Casting a tipo desconocido cuando solo se le da nombre de clase como una cadena de ese tipo

Pensé que podría usar (Class.forName (className)) list.get (i), pero recibí un error de sintaxis alegando que olvidé un punto y coma.

Desafortunadamente, dado que estoy usando Java 1.3, no tengo acceso al método Class.cast (Object).

¿Cuál es el nombre de la clase utilizada al convertir a otro tipo en Java 1.3? ¿Hay algún método que me pueda dar el tipo correcto que necesito con un parámetro String del nombre de la clase?

+0

Si actualiza su versión de java, vaya directamente a Java 6, ya que Java 5 será EOL en octubre. : -] –

Respuesta

5

No, y no puede hacer esto en la mayoría de los idiomas.

La razón es que el tipo a transmitir tiene que conocerse en tiempo de compilación, no en tiempo de ejecución (que es lo que estás tratando de hacer).

Si lo piensas bien, tiene sentido, porque dado que la variable podría ser cualquier nombre de tipo, ¿cómo se supone que debes acceder a los distintos miembros? No se puede, a menos que se definan en un tipo base/interfaz que implementen todas las instancias, en cuyo caso solo debe usar eso.

1

Supongo que realmente quería escribir lo siguiente, en lugar de usar Object en el lado izquierdo. Como de lo contrario, solo se trata de verificar si el objeto en la lista es del tipo correcto.

ClassName o = (classname)list.get(i); 

Bueno, Java está tipado estáticamente. No es posible que le dé una cuerda y le da el tipo estático correspondiente, para que pueda ir sin lanzar. Incluso con genéricos y Class<T>.cast, el tipo de destino de conversión no viene dado por una cadena, sino por el argumento genérico de tipo T, que se conoce en tiempo de compilación. Tiene que lanzar manualmente al tipo correcto, o seguir usando el tipo más común (puede ser un objeto en su caso).

Si lo hace Class.forName(className), que le devuelve un objeto del tipo Class que contiene información sobre el tipo en tiempo de ejecución, por lo que le permite hacer

Class.forName("my.stuff.MyClass").newInstance() 

Pero el elenco quiere un tipo - no un objeto de algún tipo. Es por eso que el compilador le dijo que hay algo mal con ese código.

El tipo estático de la referencia devuelta es Object. Esto es importante: el tipo dinámico de un objeto al que se hace referencia y el tipo estático de la referencia que apunta a ese objeto. El tipo dinámico del objeto es lo que puede ser "controlado" por una cadena (usando Class.forName), pero el tipo estático de la referencia que tiene que hacer en tiempo de compilación, y eso es (solo para dar un ejemplo) usado para seleccionar funciones que se sobrecargan entre sí, no se puede determinar con una cadena.

10

¿Cuál es el punto de lanzamiento cuando todo lo que hace es asignar el resultado al objeto? Todo lo que lograría sería una excepción si no implementara la interfaz/extender o fuera la clase o si no hiciera nada.

Para que un simple:

public static boolean IsInstance(object x, String className) 
    { 
    Class cls = Class.forName(className); 
    return cls.isInstance(x); 
    } 

es suficiente (y más limpio)

Si se va a la utilización de reflexión para llegar a los campos/métodos de la clase que está muy bien

+0

Ese es exactamente el punto --- falla rápido, con una excepción, justo donde está el problema, en lugar de un tiempo y lugar no especificados. – erickson

+0

¡Gracias! Eso fue muy útil –

0

La pregunta era answered ya, pero me gustaría añadir que parece un poco dudoso que usted deba tener una lista en la que conserve varios tipos diferentes de objetos (en este caso, cualquier objeto), pero tendría una Por lo general, les gusta invocar operaciones que son específicas para cada tipo diferente ...

¿Cuál es el objetivo de esta colección? Las instancias que guarda en él no tienen en común , ¿algún supertipo común en el que puedan incluirlas?

2

Un escenario donde surge la necesidad de esto es cuando se aplica la seguridad de tipo con un sistema heredado. Por ejemplo, supongamos que tiene un sistema de persistencia como Hibernate que proporciona un List sin procesar de los resultados de un método de "buscador". Al convertir este List bruto en un tipo parametrizado, se producirá una advertencia no verificada, y si la Lista contiene un objeto del tipo incorrecto, se puede generar un ClassCastException en un momento no especificado en algún código relacionado remotamente. Puede ser mejor validar los contenidos de la lista por adelantado, utilizando un mecanismo como sugiere OP.

Aquí está la versión Java 1.3 (sin genéricos):

private static void checkType(Collection objs, String className) 
    throws ClassNotFoundException 
{ 
    Class clz = Class.forName(className); 
    Iterator i = objs.iterator(); 
    while (i.hasNext()) { 
    Object obj = i.next(); 
    if (!clz.isInstance(obj)) { 
     throw new ClassCastException(); 
    } 
    } 
} 

En Java 5 y más tarde, con los genéricos, se puede hacer algo similar con el método Class.cast() para verificar el contenido de una colección, lo que justifica el uso de una anotación SuppressWarnings. En nuestro proceso de revisión, suprimir una advertencia sin alguna "prueba" de que es seguro se archiva como un error.

Cuestiones relacionadas