Ten en cuenta que en las ciencias informáticas cualquier problema casi siempere suele tener diferentes soluciones, así que aquí enseñamos la mejor y más óptimo.
Solución:
Tengo que hacerte una pregunta a cambio: ¿tu GenSet
“marcado” o “no marcado”? ¿Que significa eso?
-
Comprobado: escritura fuerte.
GenSet
sabe explícitamente qué tipo de objetos contiene (es decir, su constructor fue llamado explícitamente con unClass
argumento, y los métodos lanzarán una excepción cuando se les pasen argumentos que no sean del tipoE
. VerCollections.checkedCollection
.-> en ese caso, debe escribir:
public class GenSet
private E[] a; public GenSet(Class c, int s) // Use Array native method to create array // of a type only known at run time @SuppressWarnings("unchecked") final E[] a = (E[]) Array.newInstance(c, s); this.a = a; E get(int i) return a[i]; -
Desenfrenado: escritura débil. En realidad, no se realiza ninguna verificación de tipo en ninguno de los objetos pasados como argumento.
-> en ese caso, debe escribir
public class GenSet
private Object[] a; public GenSet(int s) a = new Object[s]; E get(int i) @SuppressWarnings("unchecked") final E e = (E) a[i]; return e; Tenga en cuenta que el tipo de componente del array debería ser el borradura del parámetro de tipo:
public class GenSet
// E has an upper bound of Foo private Foo[] a; // E erases to Foo, so use Foo[] public GenSet(int s) a = new Foo[s]; ...
Todo esto es el resultado de una debilidad conocida y deliberada de los genéricos en Java: se implementó mediante el borrado, por lo que las clases “genéricas” no saben con qué tipo de argumento se crearon en tiempo de ejecución y, por lo tanto, no pueden proporcionar tipo- seguridad a menos que se implemente algún mecanismo explícito (comprobación de tipos).
Puedes hacerlo:
E[] arr = (E[])new Object[INITIAL_ARRAY_LENGTH];
Esta es una de las formas sugeridas de implementar una colección genérica en Java efectivo; artículo 26. Sin errores de tipo, sin necesidad de emitir el array repetidamente. Sin embargo esto desencadena una advertencia porque es potencialmente peligroso y debe usarse con precaución. Como se detalla en los comentarios, este Object[]
ahora se hace pasar por nuestro E[]
y puede causar errores inesperados o ClassCastException
s si se usa de manera insegura.
Como regla general, este comportamiento es seguro siempre que el yeso array se usa internamente (por ejemplo, para respaldar una estructura de datos) y no se devuelve ni se expone al código del cliente. Si necesita devolver un array de un tipo genérico a otro código, el reflejo Array
La clase que mencionas es el camino correcto a seguir.
Vale la pena mencionar que, siempre que sea posible, se sentirá mucho más feliz trabajando con List
s en lugar de matrices si está utilizando genéricos. Ciertamente, a veces no tiene otra opción, pero usar el marco de colecciones es mucho más sólido.
A continuación se explica cómo utilizar genéricos para obtener un array precisamente del tipo que está buscando mientras preserva la seguridad del tipo (a diferencia de las otras respuestas, que le devolverán un Object
array o resultar en advertencias en tiempo de compilación):
import java.lang.reflect.Array;
public class GenSet
private E[] a;
public GenSet(Class clazz, int length)
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
public static void main(String[] args)
GenSet foo = new GenSet(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
Eso compila sin advertencias, y como puede ver en main
para cualquier tipo que declare una instancia de GenSet
como, puede asignar a
a una array de ese tipo, y puede asignar un elemento de a
a una variable de ese tipo, lo que significa que el array y los valores en el array son del tipo correcto.
Funciona mediante el uso de literales de clase como tokens de tipo de tiempo de ejecución, como se explica en los tutoriales de Java. El compilador trata los literales de clase como instancias de java.lang.Class
. Para usar uno, simplemente siga el nombre de una clase con .class
. Entonces, String.class
actúa como un Class
objeto que representa la clase String
. Esto también funciona para interfaces, enumeraciones, matrices de cualquier dimensión (por ejemplo, String[].class
), primitivas (por ejemplo int.class
), y la palabra clave void
(es decir void.class
).
Class
en sí mismo es genérico (declarado como Class
donde T
representa el tipo que el Class
el objeto está representando), lo que significa que el tipo de String.class
es Class
.
Entonces, cada vez que llamas al constructor para GenSet
pasa un literal de clase para el primer argumento que representa un array de El GenSet
tipo declarado de la instancia (p. ej. String[].class
por GenSet
). Tenga en cuenta que no podrá obtener una array de primitivas, ya que las primitivas no se pueden usar para variables de tipo.
Dentro del constructor, llamando al método cast
devuelve lo pasado Object
argumento emitido a la clase representada por el Class
objeto en el que se llamó al método. llamando al static método newInstance
en java.lang.reflect.Array
regresa como un Object
un array del tipo representado por el Class
objeto pasado como primer argumento y de la longitud especificada por el int
pasado como el segundo argumento. Llamando al método getComponentType
devuelve un Class
objeto que representa el tipo de componente del array representado por el Class
objeto sobre el que se llamó al método (p. ej. String.class
por String[].class
, null
Si el Class
objeto no representa un array).
Esa última frase no es del todo exacta. Vocación String[].class.getComponentType()
devuelve un Class
objeto que representa la clase String
pero su tipo es Class>
no Class
por lo que no puede hacer algo como lo siguiente.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Lo mismo ocurre con todos los métodos en Class
que devuelve un Class
objeto.
Con respecto al comentario de Joachim Sauer sobre esta respuesta (no tengo suficiente reputación para comentarlo yo mismo), el ejemplo que usa el elenco para T[]
dará como resultado una advertencia porque el compilador no puede garantizar la seguridad de tipos en ese caso.
Editar con respecto a los comentarios de Ingo:
public static T[] newArray(Class type, int size)
return type.cast(Array.newInstance(type.getComponentType(), size));
Puntuaciones y reseñas
Nos puedes añadir valor a nuestro contenido informacional cooperando tu veteranía en las interpretaciones.