有人能指出我在Java中使用泛型的好例子吗?我是指自己写一个通用类的例子吗?
大多数解释都是“您可以定义这样的泛型类。现在请参阅Java Collections API并忘记所有这些 - 只需使用它并感到高兴。”
我想要的更像是“你可以像这样定义一个泛型类,现在考虑一下你可能想要它的情况,现在让我们看看我们如何编写它。”
感谢。
答案 0 :(得分:8)
Java中的泛型促进parametric polymorphism。通过类型参数,您可以将参数传递给类型。正如像String foo(String s)
这样的方法模拟某些行为,不仅是针对特定字符串,而是针对任何字符串s
,因此像List<T>
这样的类型会对某些行为进行建模,而不仅仅针对特定类型,但适用于任何类型。 List<T>
表示适用于任何类型T
,List
个T
。所以List
实际上是一个类型的构造函数。它将一个类型作为参数,并构造另一个类型作为结果。
以下是我每天使用的一般类型的几个示例。首先,一个非常有用的通用接口:
public interface F<A, B> {
public B f(A a);
}
此接口说明适用于任何两种类型A
和B
,有一个函数(称为f
),它接受A
并返回{ {1}}。当您实现此界面时,B
和A
可以是您想要的任何类型,只要您提供的函数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)
一些有用的练习:
我不能马上给你代码示例,因为我正在研究它们,但也许你可以尝试自己做,然后如果你被卡住了就回来再提问。
答案 7 :(得分:0)
我认为泛型的好例子是Java SE的集合类 你有很好的文档和很多源代码需要检查。