Java本土增长的泛型示例

时间:2009-04-02 21:00:12

标签: java generics

有人能指出我在Java中使用泛型的好例子吗?我是指自己写一个通用类的例子吗?

大多数解释都是“您可以定义这样的泛型类。现在请参阅Java Collections API并忘记所有这些 - 只需使用它并感到高兴。”

我想要的更像是“你可以像这样定义一个泛型类,现在考虑一下你可能想要它的情况,现在让我们看看我们如何编写它。”

感谢。

8 个答案:

答案 0 :(得分:8)

Java中的泛型促进parametric polymorphism。通过类型参数,您可以将参数传递给类型。正如像String foo(String s)这样的方法模拟某些行为,不仅是针对特定字符串,而是针对任何字符串s,因此像List<T>这样的类型会对某些行为进行建模,而不仅仅针对特定类型,但适用于任何类型List<T>表示适用于任何类型TListT 。所以List实际上是一个类型的构造函数。它将一个类型作为参数,并构造另一个类型作为结果。

以下是我每天使用的一般类型的几个示例。首先,一个非常有用的通用接口:

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

此接口说明适用于任何两种类型AB,有一个函数(称为f),它接受A并返回{ {1}}。当您实现此界面时,BA可以是您想要的任何类型,只要您提供的函数B可以使用前者和返回后者。以下是界面的示例实现:

f

在泛型之前,使用F<Integer, String> intToString = new F<Integer, String>() { public String f(int i) { return String.valueOf(i); } } 关键字通过子类化实现多态性。使用泛型,我们实际上可以取消子类化并使用参数多态。例如,考虑用于计算任何类型的哈希码的参数化(通用)类。我们不会覆盖Object.hashCode(),而是使用这样的泛型类:

extends

这比使用继承更灵活,因为我们可以保持使用组合和参数多态的主题,而不会锁定脆弱的层次结构。

但是,Java的泛型并不完美。例如,您可以抽象类型,但不能抽象类型构造函数。也就是说,您可以说“对于任何类型T”,但您不能说“对于任何类型T采用类型参数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.。如果您还没有,请查看标准Java库的源代码。

答案 1 :(得分:3)

你的答案在Java Generics FAQ中得到了部分回答,它提供了一些很好的例子,说明你希望你的班级成为一个普通班级。另请参阅常见问题解答中的Designing Generic Methods部分。

答案 2 :(得分:2)

我使用泛型来处理DAO中的一些基本CRUD操作。大部分代码都会被各种域对象复制,所以我尽可能地将其提取到一个通用的抽象类中。

答案 3 :(得分:2)

不确定这正是您正在寻找的,但是对于示例......您创建的任何类型的数据结构都可以(并且可能应该)以通用形式完成。我曾经这样开过一个:

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

当然,这依赖于泛型的另一种用法,这个界面的元素是相互可比的序列:

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

我还创建了一整套节点类,如

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> { ... }

可以设想用于创建图形,树,链表等以及Algorithms类,它具有在这些节点上运行的各种(通用!)方法。

或者,如果您厌倦了数据结构,其他一些想法包括可以转换为类型的东西的接口:

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

或一个用于字符串解析器:

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

或者一个用于自己的解析器的类:

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

我用它来创建一个解析命令行选项的系统:

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

等。等等。

答案 4 :(得分: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; }
}

答案 5 :(得分:1)

使用泛型的静态实用程序函数的示例。它需要两张地图,A - &gt; B和B - &gt; C并构建A - > C(哈希)映射。

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;
}

使用示例:

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);
    }
}

结果:

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

无论如何,我试图说明的是使用泛型,你可以创建一些非常有用的,通用的实用函数。

答案 6 :(得分:0)

一些有用的练习:

  • 编写自己的ArrayList实现
  • 编写一个基本的Map实现(不需要担心那里的效率,如果你需要遍历一个完整的数组来找到它,那就去做吧)。
  • 将您的Map impl子类化。计算键的值写入,使用自定义Map.Entry,该方法具有返回写入计数的方法

我不能马上给你代码示例,因为我正在研究它们,但也许你可以尝试自己做,然后如果你被卡住了就回来再提问。

答案 7 :(得分:0)

我认为泛型的好例子是Java SE的集合类 你有很好的文档和很多源代码需要检查。