Ingresar:

programacion java :: Blog :: Genéricas, arreglos y subtipos

February 28, 2007

E: ¿Qué es un arreglo?

M: Una estructura que tiene para cada elemento: un identificador y una casilla que puede contener un valor.

E: ¿De dónde viene el arreglo?

M: De una abstracción de un bloque de memoria, cuyos elementos son fácil y rápidamente accesibles porque son contiguos y basta hacer aritmética para ubicar un elemento a partir de la dirección de memoria del primero. El compilador se encarga de hacer todos los cálculos. El programador piensa en índices del arreglo.

E: No me dejo entender, conceptualmente ¿qué es?

M: Entonces es como conjunto de pares de elementos. Cada par contiene: una llave que es aquel dato que nos ayuda a identificar un valor. Es un conjunto por que sus pares no se pueden repetir (para evitar ambiguedad, ya que la búsqueda se realiza por llave).

E: ¿Eso no llaman en Java un Map?

M: Eso es lo que es. Map<K,V>, donde K es un Int (o un Integer si eres purista) y V representa el tipo de los elementos del arreglo.

E: Yo necesito representar un arreglo cuyos elementos estén parametrizados en el tipo.

M: ¿? Ya están. No entiendo. El tipo de un arreglo es básicamente: Map<Integer,V>.  ¿Quieres más genérico que V?

E: Si, quiero un tipo que dependa de un tipo: V<T>.

M: Ah, y ¿cuál es el problema de Map<Integer,V<T>>?

E: Eh, uh. Compila. Corre. (asombrado, cara de alegría). En realidad yo buscaba un arreglo, no un Map. Yo quería un
        E<T> [] arreglo
Es que un arreglo es más rápido...

M: Ah ... arreglos. Los arreglos en Java son una estructura excepcional. Esto hace que el lenguaje no sea tan simple como querían sus creadores. Lo mismo pasa con los tipos primitivos. No importa. ¿Qué te parece la siguiente instrucción?
        List <String> ls = new ArrayList<String>();

E: Perfectamente legal.

M: ¿Y si luego tengo la siguiente instrucción?
        List <Object> lo = ls;

E: Mmmm, me parece que no tendría que tener problema. (Prueba en su compilador). Ups, error de compilación. No entiendo. ¡Pero si una lista de String es una lista de Object! (Cara de preocupado)

M: Veamos. Si fuera cierto, ¿podríamos hacer lo siguiente?
        lo.add(new Object());

E: No le veo problema. En las condiciones que estamos presuponiendo debiera funcionar.

M: Entonces también podríamos hacer lo siguiente:
        String s = ls.get(0);

E: Ups. No es verdad. Eso no se puede. Esto está medio raro, ¿por qué me complicas la vida?

M: Yo no la complico, se complica cuando un lenguaje de programación es parchado muchas veces, se pierde la coherencia. El problema es que la introducción de genéricas ha modificado las relaciones de subtipo. En general, si Foo es una subclase de Bar, y G es una declaración genérica G<Foo> no es subtipo de G<Bar>.

E: ¿Y esto que tiene que ver con los arreglos?

M: Primero que es una prueba de que con genéricas ya no funciona el mismo razonamiento. Segundo que básicamente los arreglos son una especie de genérica con un parámetro fijo, por tanto el problema de los subtipos existe. Tercero que hemos entrado en una forma de razonamiento para explicar por qué no puedes hacer lo que quieres en Java.

E: Entiendo.

M: Supongamos que esta línea de código tiene sentido:
        List<String> lsa = new List<String>[10];
Esto es algo parecido a lo que quieres, ¿no?

E: (Alegre) ¡Si!

M: Entonces tendría sentido hacer lo siguiente, ¿verdad?
        Object o = lsa;
        Object [] oa = (Object []) o;

E: En principio, con las reglas que me son familiares parece coherente.

M: ¿Y se podría hacer lo siguiente?
        List<Integer> li = new ArrayList<Integer>();
        li.add(new Integer(3));
        oa ...
       
E: (Interrumpe). Eso parece Java normal ...

M: Es verdad, pero no te impacientes. Decía:
        oa[1] = li;
        Str...

E: (Interrumpe). Esto parece medio raro, sin embargo respecto a la seguridad de uso de memoria parece razonable.

M:        String s = lsa[1].get(0);

E: Ah, entiendo. Me daría una excepción ClassCastException.

M: Exacto. Provino de suponer que se podía hacer lo que pensabamos. Pero Java tiene que ser un lenguaje seguro ante todo, por tanto esto no es posible.

---

El material para este diálogo fue extractado del tutorial de Java en la sección de generics.

 

Enviado por Pablo Azero @ programacion java



Comentarios

  1. Bueno entiendo todos estos detalles, se que puedo utilizar otras estructuras, el caso surgio cuando estaba implementando un arbol n-ario haciendo uso de arreglos, obteniendo lo siguiente:

    class ArbolN<T extends Comparable<T>> {      private T raiz;      /* Hago lo siguiente pues creo que los hijos tambien tienen que ser árboles con       * el parámetro T, esto me parece bastante lógico */     private ArbolN<T>[] hijos     public ArbolN( int tam ) {        raiz = null;        //  AQUI surgió el problema, esto me parece bastante logico        hijos = new ArbolN[ tam ];     }     public T getRaiz(){          return raiz;     } }    

    Obviamente todo funciona como se espera, el detalle es que pienso que usando los arreglos estos deberian ser parametrizados, pues como dice el doctor tengo que asegurarme que las operaciones sean seguras, para lo que cuando yo pida la raiz de algún hijo, me retorne de tipo T. Además entiendo que cuando definimos el tamaño del arreglo, se esta resevando espacio en memoria, y pues si voy a tener una referencia ArbolN<T>, se deberia reservar espacio para ArbolN, con parámetro T. Ahora bien si quitamos el parametro al arreglo, no se como podriamos asegurarnos que el elemento a manejar en el arbol sea parametrizado de manera segura.

    Estoy seguro de que puedo hacerlo usando otras estructuras, de otra manera, entiendo que no puedo copiar la referencia de un objeto parametrizado con un tipo, a otra referencia parametrizada con otro tipo, pues seria un "GRAN" error. Ejemplo:
    ArrayList<String> lista = new ArrayList<String>();
    ArrayList<Object> listaObj = lista; // ERROR

    no olvidemos que al hacer la segunda asignación estoy tratando de poner un ArrayList de String en uno de Object, parece lógico, pero el problema es que estaria con listaObj, estaria apuntando a la misma referencia de lista, y pues prodria hacer operaciones como esta:
    listaObj.add( new Object() );  // He aqui el gran error

    Bueno a que me voy con eso es que
    Primero : A momento de construir un objeto parametrizado le enviamos el parámetro, pienso que lo mismo deberia hacerse con los arreglos (se que los arreglos son distintos)
    Segundo: Se estaría limitando a que el tipo del arreglo no pueda ser parametrizado, creo eso me límita en algo y eso no me gusta.
    Tercero: Al no poner el parámetro, me sale un warning, como dice el doctor son como parches, pero no veo por que no poder parametrizarlo. Espero opiniones...

    PD. No es por terco, solo hago lo que pienso que es correcto, entiendo la información proporcionada, pero aún asi no veo el porque me limiten este detalle. 

    user iconWilfredo Vargas on Wednesday, 28 February 2007, 19:41 BOT # |

  2. Me gustaria saber si encontraste una respuesta a tu problema, es muy interesante, gracias.

    user iconShavila on Saturday, 07 July 2007, 03:29 BOT # |

Debes iniciar sesión para enviar un comentario.