Saltar al contenido

Cómo crear un genérico array en Java?

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 un Class argumento, y los métodos lanzarán una excepción cuando se les pasen argumentos que no sean del tipo E. Ver Collections.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 ClassCastExceptions 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 Lists 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 mainpara 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 Classdonde 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 GenSetpasa 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 Stringpero su tipo es Classno Classpor 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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *