2012-09-11 25 views
20

Lo que ocurre dentro de Java ArrayList<T> (y probablemente muchas otras clases) es que hay un Object[] array = new Object[n]; interno, al que se escriben T Objetos. Cada vez que se lee un elemento, se realiza una conversión return (T) array[i];. Entonces, un elenco en cada lectura.¿Por qué Java ArrayList usa conversión por elemento en lugar de conversión por matriz?

Me pregunto por qué se hace esto. Para mí, parece que solo están haciendo moldes innecesarios. ¿No sería más lógico y también un poco más rápido crear un T[] array = (T[]) new Object[n]; y luego solo return array[i]; sin yeso? Esto es solo un lanzamiento por creación de matriz, que generalmente es muy por debajo del número de lecturas.

¿Por qué es preferible este método? ¿No veo por qué mi idea no es estrictamente mejor?

+0

Porque un 'Objeto []' no es un 'T []'. Ver http://stackoverflow.com/a/6709604/238419 –

Respuesta

17

Es más complicado que eso: los genéricos se borran en el código de bytes, y la eliminación de T[] es Object[]. Del mismo modo, el valor de retorno de get() se convierte en Object. Para conservar la integridad del sistema de tipo, se inserta un elenco comprobado cuando se utiliza realmente la clase, es decir,

Integer i = list.get(0); 

se borrarán para

Integer i = (Integer) list.get(0); 

Siendo ese el caso, ninguna verificación de tipo dentro de ArrayList es redundante. Pero realmente no viene al caso, porque tanto (T) como (T[]) son destrabados lanzamientos, y no incurren en sobrecarga de tiempo de ejecución.

Se podría escribir una ArrayList comprobado que hace:

T[] array = Array.newInstance(tClass, n); 

Esto impediría contaminación montón, pero al precio de un cheque de tipo redundante (no se puede suprimir el elenco synthentic en código de llamada). También requeriría que la persona que llama le proporcione a ArrayList el objeto de clase del tipo de elemento, lo que desordena su API y hace que sea más difícil de usar en un código genérico.

Editar: ¿Por qué está prohibida la creación de matriz genérica?

Un problema es que las matrices están marcadas, mientras que los genéricos están desmarcados. Es decir:

Object[] array = new String[1]; 
array[0] = 1; // throws ArrayStoreException 

ArrayList list = new ArrayList<String>(); 
list.add(1); // causes heap pollution 

Por lo tanto, importa el tipo de componente de una matriz. Supongo que es por eso que los diseñadores del lenguaje Java requieren que seamos explícitos sobre qué tipo de componente usar.

+0

Hmm ... interesante. Pero si ninguno de los dos incurre en tiempo de ejecución, ¿por qué hay tanto alboroto sobre la "creación de matriz genérica"? ¿Por qué no puede el compilador simplemente reemplazar 'T [] array = new T [n]' por 'T [] array = (T []) new Object [n]' como un servicio de azúcar sintáctico? – user1111929

-1

La matriz también es un objeto. Aquí T[] array = (T[]) new Object[n] solo lanza (T []) tipo de objeto no elementos en la matriz.

3

Cada vez que se lee un elemento, se realiza una conversión return (T) array[i];. Entonces, un elenco en cada lectura.

Generic es una comprobación de tiempo de compilación. En tiempo de ejecución, se usa el tipo T extends en su lugar. En este caso T implícitamente extends Object por lo que lo que tiene en tiempo de ejecución es efectivamente.

return (Object) array[i]; 

o

return array[i]; 

¿No sería más lógico y también ligeramente más rápido que acaba de crear un

T[] array = (T[]) new Object[n] 
No

realmente. Una vez más en tiempo de ejecución esto se convierte en

Object[] array = (Object[]) new Object[n]; 

o

Object[] array = new Object[n]; 

Lo que en realidad está pescando para

T[] array = new T[n]; 

excepto que esta no se compila, sobre todo porque T no se conoce en tiempo de ejecución .

Lo que puede hacer es

private final Class<T> tClass; // must be passed in the constructor 

T[] array = (T[]) Array.newInstance(tClass, n); 

sólo entonces la matriz ser en realidad el tipo esperado. Esto podría hacer que las lecturas sean más rápidas, pero a costa de las escrituras. El principal beneficio sería una verificación rápida de fallas, es decir, impediría que una colección se corrompa en lugar de esperar hasta que detecte que está corrupta para lanzar una excepción.

1

Creo que es más una cuestión de estilo de código no de rendimiento o tipo de seguridad (porque la matriz de soporte es privado)

El java 5 ArrayList se puso en práctica la manera que usted sugiere con una serie E[]. Si miras el código fuente, ves que contiene 7 (E []) lanzamientos. Desde java 6, el ArrayList cambió para usar una matriz Object[] que dio como resultado solo 3 (E) lanzamientos.

Cuestiones relacionadas