2009-04-02 19 views
8

¿Alguien me puede indicar buenos ejemplos del uso de genéricos en Java? ¿Con esto quiero decir ejemplos de escribir una clase genérica uno mismo?Ejemplos de genéricos de fabricación casera de Java

La mayoría de las explicaciones dicen "Puedes definir una clase genérica como esta. Ahora mira la API de colecciones de Java y olvídate de todo eso, solo úsala y sé feliz".

Lo que quiero es algo así como "Puedes definir una clase genérica como esta, ahora considera este caso donde lo desees, ahora veamos cómo lo escribimos".

Gracias.

Respuesta

0

Un par de ejercicios útiles:

  • escribir su propia implementación ArrayList
  • escribir una aplicación de mapas básicos (no hay necesidad de preocuparse por la eficiencia allí, si es necesario atravesar toda una serie de encontrar algo, hacerlo)
  • subclase tu mapa impl. para contar escrituras de valor para una clave, con un Map.Entry personalizado que tiene un método que devuelve el recuento de escritura

No puedo darle ejemplos de código de inmediato, porque estoy trabajando en ellos, pero tal vez podría tratar de hacerlas usted mismo, y volver con más preguntas si está atrapado.

+0

Cualquier cosa de bajo nivel que realmente desee implementar con matrices es probablemente un mal ejemplo. –

3

Su respuesta se responde parcialmente en el Java Generics FAQ, que ofrece algunos buenos ejemplos de cuándo desea que su clase sea una clase genérica. Consulte también la sección Designing Generic Methods en las Preguntas frecuentes.

2

He usado genéricos para tratar algunas operaciones CRUD básicas en un DAO. Gran parte del código se habría duplicado para varios objetos de dominio, de modo que, en la medida de lo posible, extraje en una clase abstracta genérica.

+1

+1 para esto. Si usa Hibernate y Java, hay un buen artículo de IBM (sorpresa) sobre el tema: http://www.ibm.com/developerworks/java/library/j-genericdao.html – duffymo

2

No estoy seguro de que esto sea exactamente lo que está buscando, pero como ejemplos ... cualquier tipo de estructura de datos que cree puede (y probablemente deba) hacerse en forma genérica. I una vez iniciado uno como este:

public class TrieMap<C extends Comparable<C>, K extends ComponentComparable<C>, V> 
extends AbstractMap<K,V> implements SortedMap<K,V> { 
    ... 
} 

Y, por supuesto, que dependía de otro uso de genéricos, esta interfaz para las secuencias de cuyos elementos son mutuamente comparables:

public abstract interface ComponentComparable<C extends Comparable<C>> 
extends Comparable<ComponentComparable<C>>, Iterable<C> { 
    ... 
} 

También creé todo un conjunto de clases de nodos como

public interface Node<T extends Node<T>> { ... } 
public interface TreeNode<T extends TreeNode<T>> extends Iterable<T>, Node<T> { ... } 
public interface ListNode<T extends ListNode<T>> extends Node<T> { ... } 
public interface BinaryTreeNode<T extends BinaryTreeNode<T>> extends Node<T> { ... } 
public interface TernaryTreeNode<T extends TernaryTreeNode<T>> 
extends BinaryTreeNode<T> { ... } 

la que posiblemente podría ser útil para la creación de gráficos, árboles, listas enlazadas, etc., junto con una clase Algorithms que tiene toda sor ts de métodos (genéricos) para operar en estos nodos.

O si estás harto de estructuras de datos, algunas otras ideas incluyen una interfaz para las cosas que se puede convertir a un tipo:

public abstract interface Convertable<T> { 
    public abstract T convert(); 
} 

o uno de los analizadores de cadena:

public interface Parser<O> { 
    public abstract O parse(String str); 
} 

o uno para las clases que son sus propios programas de análisis:

public interface Parseable<P extends Parseable<P>> extends Parser<P> {} 

que he utilizado en la creación de un sistema a la par SE opciones de línea de comandos:

public abstract class Option<T> { ... } 
public class CLOption<P extends Parseable<P>> extends Option<P> { ... } 
public class StringOption extends Option<String> { ... } 

etc etc etc

2
public class Pair<A,B> { 
    private A a; 
    private B b; 
    public Pair(A a, B b) { setFirst(a); setSecond(b); }  
    public A getFirst() { return a; } 
    public B getSecond() { return b; } 
    public void setFirst(A a) { this.a=a; } 
    public void setSecond(B b) { this.b=b; } 
} 
+0

Me gusta que sea inmutable. –

8

genéricos en Java facilitan parametric polymorphism. Por medio de parámetros de tipo, puede pasar argumentos a tipos. Así como un método como String foo(String s) modela cierto comportamiento, no solo para una cadena en particular, sino para cualquier cadena s, un tipo como List<T> modela cierto comportamiento, no solo para un tipo específico, sino para cualquier tipo. List<T> dice que para cualquier tipo T, existe un List de T s. Entonces List es en realidad un tipo constructor. Toma un tipo como argumento y construye otro tipo como resultado.

Aquí hay un par de ejemplos de tipos genéricos que uso todos los días. En primer lugar, una interfaz genérica de gran utilidad:

public interface F<A, B> { 
    public B f(A a); 
} 

Esta interfaz dice que para cualquier par de tipos, A y B, hay una función (llamada f) que toma un A y devuelve un B. Al implementar esta interfaz, A y B pueden ser de cualquier tipo que desee, siempre y cuando proporcione una función f que tome la primera y devuelva la última. He aquí un ejemplo de implementación de la interfaz:

F<Integer, String> intToString = new F<Integer, String>() { 
    public String f(int i) { 
    return String.valueOf(i); 
    } 
} 

Antes de genéricos, el polimorfismo se logró mediante la subclasificación usando la palabra clave extends. Con los genéricos, en realidad podemos eliminar la subclasificación y usar polimorfismo paramétrico. Por ejemplo, considere una clase parametrizada (genérica) utilizada para calcular códigos hash para cualquier tipo. En lugar de anular Object.hashCode(), usaríamos una clase genérica de esta manera:

public final class Hash<A> { 
    private final F<A, Integer> hashFunction; 

    public Hash(final F<A, Integer> f) { 
    this.hashFunction = f; 
    } 

    public int hash(A a) { 
    return hashFunction.f(a); 
    } 
} 

Esto es mucho más flexible que el uso de la herencia, porque podemos permanecer con el tema de la utilización de la composición y el polimorfismo paramétrico sin bloquear abajo jerarquías frágiles.

Los genéricos de Java no son perfectos. Puede abstraer sobre tipos, pero no puede abstraer sobre constructores de tipo, por ejemplo. Es decir, puede decir "para cualquier tipo T", pero no puede decir "para ningún tipo T que tenga un parámetro de tipo A".

I wrote an article about these limits of Java generics, here.

The source for a lot of useful generic types can be found here.. Consulte también la fuente de la biblioteca Java estándar, si aún no lo hizo.

1

Un ejemplo de una función de utilidad estática usando genéricos. Toma dos mapas, A -> B y B -> C y construye un mapa A -> C (hash) a partir de él.

public static <A, B, C> Map<A, C> transitise(Map<A, B> aToB, Map<B, C> bToC) { 
    HashMap<A, C> map = new HashMap<A, C>(aToB.size() * 2); 
    for (Map.Entry<A, B> abEntry : aToB.entrySet()) { 
     map.put(abEntry.getKey(), bToC.get(abEntry.getValue())); 
    } 
    return map; 
} 

Ejemplo Uso:

public static void main(String[] args) { 
    HashMap<String, Integer> nameToNumber = new HashMap<String, Integer>(); 
    nameToNumber.put("Anna", 12345); 
    nameToNumber.put("James", 444); 
    HashMap<Integer, Point> numberToPosition = new HashMap<Integer, Point>(); 
    numberToPosition.put(12345, new Point(3, 3)); 
    numberToPosition.put(444, new Point(1, 55)); 
    for (Map.Entry<String, Point> nTP : 
     transitise(nameToNumber, numberToPosition).entrySet()) 
    { 
     System.out.println(nTP.getKey() + " -> " + 
      nTP.getValue().x + "/" + nTP.getValue().y); 
    } 
} 

Resultados en:

James -> 1/55 
Anna -> 3/3 

De todos modos, lo que estoy tratando de ilustrar es que el uso de los genéricos, se puede hacer algo muy útil, er, funciones genéricas de utilidad.

0

Creo que buenos ejemplos de genéricos son las clases de colección de Java SE.
Obtuvo buena documentación y una gran cantidad de código fuente para examinar.