2

我知道基于对象的集合是泛型的主要候选者,并且已经在集合库中泛型。除此之外,一个类或接口应该具备哪些属性和行为才能使其成为泛化的候选者?为什么例如 ThreadLocal类或AtomicReference类被泛化?是什么导致了这个设计决策?

4

5 回答 5

3

需要为不同类型重用的类始终是泛型的候选者。例如class Pair<U,V>

于 2013-02-20T18:37:50.623 回答
3

如果一个类可以与各种其他类具有相同的关系,那么该类是泛化的一个很好的候选者。集合类是通用的,因为关系“包含”可以应用于任何对象类。Comparable和接口是通用的Comparator,因为“可以比较”的关系可以应用于许多不同的对象(尽管实际上这仅限于类自己的层次结构中和周围的对象Comparable)。

此外,如果您发现自己编写了多个非常相似的类,唯一的区别是您正在操作的对象的类型,那么请考虑编写一个泛型类。

编辑:

使用内置类AtomicReferenceThreadLocal,“包含”关系适用于各种对象类型。一个AtomicReference和一个ThreadLocal对象仍然包含另一个类型的对象。这允许以类型安全的方式设置和返回特定类型,而无需让“get”和“set”方法返回/获取,Object并且在调用“get”时无需转换返回类型“ 方法。该关系适用于特定类型,但在类设计时不需要知道确切的类型。

编辑2:

我能想到的用于使类泛型的大多数示例都涉及“包含”关系。然而,这只是泛型关系的一个具体示例,尽管 Collections 框架是基于“包含”关系的,并且它提供了许多“包含”泛型类。泛型关系不一定是“包含”,所以我将尝试举例说明可以泛化但关系是“包含”的地方。

想象一个抽象Shape类,具有具体的类,如LineSquareCircle等。现在我们定义ShapeDrawer知道如何绘制形状的接口。这里的关系是“平局”。我们可以定义接口:

public interface ShapeDrawer {
   public void drawShape(Shape shape);
}

现在我们需要ShapeDrawer专门针对特定形状的特定具体实现,例如CircleDrawerSquareDrawer

public class CircleDrawer implements ShapeDrawer {
   public void drawShape(Shape shape) {/*...*/}
}

现在drawShape方法 inCircleDrawer必须在绘制它之前测试它shape是否是 a 。Circle

现在,使用泛型的解决方案:

public interface ShapeDrawer<T extends Shape> {
   public void drawShape(T shape);
}

现在,一个实现可以绘制一个特定的Shape

public class CircleDrawer implements ShapeDrawer<Circle> {
    public void drawShape(Circle circle) {/*...*/}
}
于 2013-02-20T18:38:03.747 回答
1

数据结构应该是通用的,因为该结构应该能够处理不止一种类型的输入。

任何可以/应该被一种以上数据类型使用的类都应该以通用方式创建。

于 2013-02-20T18:38:58.940 回答
1

不要寻找“泛化”的东西。相反,您应该使用泛型以您认为最合适的方式完成特定任务。泛型只是工具箱中用于完成任务的工具。

如果您的问题是什么类型的东西可能是最好的通用实现,那么您自己的示例就是一个主要示例。当您需要以类似的方式处理不同的结构(如列表)时,泛型是一个很好的解决方案。这包括以类不变的方式处理其他类的大多数类,或者在类的子部分上是不变的。

于 2013-02-20T18:39:18.927 回答
1

每当您发现自己在铸造一个值时,您都应该考虑泛化是否会让您删除该铸造。让我们举个例子,ThreadLocalAtomicReference。两次使用返回的值get()都需要强制转换(至少在大多数情况下)。

请记住,泛型可能非常嘈杂。权衡成本和收益。尤其要考虑泛型化是否有利于 API 用户或只是你,实施者。

于 2013-02-20T19:48:53.033 回答