75-62 Técnicas de Programación Concurrentes II Lic. Ing. Osvaldo Clúa 2008 Facultad de Ingeniería Universidad de Buenos Aires Java Generics Programación Genérica ● Los programas se escriben en función de tipos que se especificarán mas tarde. FIUBA 2008 – Permite escribir algoritmos mas generales. – Existen en Ada, Eiffel, Java, C#, Visual Basic .NET y Haskell. – En C++ hay una facilidad parecida en precompilación conocida como Templates 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 2 Generics en Java ● ● Java puede tener Clases, tipos y Métodos Genéricos. – Proveen una forma de chequear tipos en compilación. – Manteniendo los programas legibles y expresivos. También se conoce esta propiedad como Polimorfismo Paramétrico o de Tipos. FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 3 Motivación ● Se quiere imprimir un arreglo sin conocer el tipo de sus elementos. public static <E> void printAr(E a[]){ int i=0; for (E elem:a) System.out.println((i++)+")="+elem); } public static void main(String[] args) { Integer ia[]={10,20,30,40}; Double da[]={7.5,3.4,5.6}; String sa[]={"En","un","overo","rosao"}; printAr(ia); printAr(da); printAr(sa); } } FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 4 Ejercicios ● ¿Cómo infiere el tipo del parámetro de printAr(...) en los llamados? – ● ¿Puede llamarse especificando el tipo: Gene01.printAr <String []>(...) ? Resolver este mismo ejemplo usando: – Polimorfismo. – Sobrecarga de métodos. FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 5 Un Ejemplo ● Se desarrollará una pila y una lista usando Generics. – El layout del código se optimizó para que cupiera en las slides. ● ● Se quitaron líneas en blanco y comentarios javadoc que son obligatorios en las entregas. La pila y la lista funcionan sobre dos clases base ejemplo: Fracción y java.lang.Integer FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 6 La clase base Fracción (1) public class Fraccion { private int num; private int den; public Fraccion(){num=1; den=1;} public Fraccion(Fraccion f){num=f.num; den=f.den;} public Fraccion(int n,int d) { setNum(n); setDen(d); normalizar(); } public int getNum() { return num; } public void setNum(int num) { this.num = num; normalizar(); } public int getDen() { return den; } FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 7 La clase base Fracción (2) public void setDen(int den) { this.den = den; normalizar(); } private void normalizar(){ int mcd=Math.abs(mcd(num,den)); num=num/mcd; den=den/mcd; } static private int mcd(int x,int y){ if (y==0)return x; else return mcd(y, x%y); } public String toString(){ return num+"/"+den; } } FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 8 La Pila Genérica import Fraccion.Fraccion; public class PilaGen<E> { class NodoGe { E dato; NodoGe sig; NodoGe(E o, NodoGe s) { dato = o; sig = s; } } NodoGe top; public PilaGen() { top = null; } public void push(E o) { top = new NodoGe(o, top); } public E pop() { E x = top.dato; top = top.sig; return x; } public boolean isEmpty() { return top == null;} FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 9 Prueba de la Pila Genérica i public static void main(String[] args) { PilaGen<Fraccion> pila = new PilaGen<Fraccion>(); PilaGen<Fraccion> pila1 = new PilaGen<Fraccion>(); // error al tratar de infiltrar un Integer, detectado en compilacion // pila.push (new Integer(3)); pila.push(new Fraccion(7, 3)); pila.push(new Fraccion(4, 5)); pila.push(new Fraccion(3, 4)); //saca de pila y pone en pila1 while (!pila.isEmpty()) { Fraccion o = pila.pop(); System.out.println("retirado " + o); pila1.push(o); } //saca de pila1 y accede al denominador while (!pila1.isEmpty()) { System.out.println("Denominador " + (pila1.pop()).getDen()); } } } FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 10 Ejercicios ● Hacer un programa similar usando polimorfismo. – Todos son descendientes de Object. – ¿Qué pasa con el error al “infiltrar” un Integer? FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 11 La Lista Genérica ● FIUBA 2008 Es un código parecido con los métodos de la figura. – También usa una clase interna Nodo. – Los métodos privados se usan para recursividad. 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 12 Un Sort genérico public class Utiles{ static <E> void sortSel (ListaGen <E> l, Comparator <E> c) { for (int i=0;i<=l.size();i++){ E uno=l.datAt(i); for (int j=i+1;j<l.size();j++){ E dos=l.datAt(j); if (c.compare(uno,dos)>0){ l.ponerEn(j,uno); l.ponerEn(i,dos); uno=l.datAt(i); } } } } } FIUBA 2008 Es un sort por selección en una class de utilitarios. ● Recibe una ListaGen y un comparador. ● 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa ● ● Que devuelve (-1,0,1) Como el pedido por la interface java.util.Comparator 13 Prueba de la Lista Genérica import Integer.IntCmp; import Fraccion.FracCmp; import Fraccion.Fraccion; public class PruLG { public static void main(String[] args) { ListaGen<Integer> li = new ListaGen<Integer>(); li.agregar(13); li.agregar(54); li.agregar(2); li.agregar(23); li.print(); Utiles.sortSel(li, new IntCmp()); li.print(); FIUBA 2008 ListaGen<Fraccion> lf = new ListaGen<Fraccion>(); lf.agregar(new Fraccion(2, 4)); lf.agregar(new Fraccion(1, 3)); lf.agregar(new Fraccion(1, 16)); lf.agregar(new Fraccion(5, 8)); lf.agregar(new Fraccion(7, 17)); lf.print(); Utiles.sortSel(lf, new FracCmp()); lf.print(); } } Los Comparator está en clases apartes (FracCmp e IntCmp) 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 14 Usando Clases anónimas ● Para las llamadas al sort podría usarse Utiles.sortSel(li, new Comparator<Integer>() { public int compare(Integer o1, Integer o2) { return o1 – o2; } }); Utiles.sortSel(lf, new Comparator<Fraccion>() { public int compare(Fraccion o1, Fraccion o2) { return (int) Math.signum(((double) o1.getNum() / (double) (o1.getDen())) ((double) o2.getNum() / (double) (o2.getDen()))); } }); FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 15 Wildcard type (?) ● Se usa para imponer alguna restricción en los tipos usados como argumentos. – <? extends Base > significa que admite cualquier tipo que extienda a la clase Base. – <? super Base > significa que admite cualquier tipo que sea supertipo de la clase Base. – <?> significa que admite cualquier tipo (sin nombrarlo). FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 16 Type erasure ● ● En compilación se verifican los tipos de los parámetros y argumentos Generics. – Después se pierde toda información sobre el tipo. – Este procedimiento se llama type erasure. Hay una sola copia del código de la estructura genérica, compartido por todas sus instancias FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 17 ¿Cuál es el tipo? public static void main(String[] args) { ListaGen<Integer> li = new ListaGen<Integer>(); ListaGen<Float> lf = new ListaGen<Float>(); if (li.getClass() == lf.getClass()) { System.out.println("Iguales"); } else { System.out.println("Distintas"); } System.out.println("El tipo de lf es: "+lf.getClass().getName()); } ● Li y lf son listas de distintos tipos. – ● Esta información se pierde en ejecución. Las estructuras genéricas no pueden ser static. FIUBA 2008 75-08 Sistemas Operativos Prof. Lic. Ing. Osvaldo Clúa 18