今天看到几个类似的问题 - 让我思考:
什么时候使用泛型的规则是什么?
- 何时涉及收藏?
- 什么时候有返回集合元素的 getter 方法?
- 对象在其生命周期内是否改变类型?
- 关系是否是类的组合/聚合?
关于您应该问自己以确定是否应该使用泛型的问题似乎没有达成共识。这纯粹是一个自以为是的决定吗?
问什么时候不应该使用泛型更容易吗?
在回到项目符号列表的第一点之前,让我先从一些关于泛型和类型信息的一般要点开始。
你还记得在泛型出现之前的 Java 吗?类型转换无处不在。
这就是类型转换的本质:您正在告诉编译器对象的类型,因为编译器不知道或无法推断它。
类型转换的问题是你有时会犯错误。您可以向编译器建议类的实例Fiddle
是Frobble
( (Frobble)fiddle
),编译器会很高兴地相信您并编译您的源代码。但如果事实证明你错了,你会在很久以后得到一个很好的运行时错误。
泛型是让编译器保留类型信息的一种不同且通常更安全的方法。基本上,编译器比人类程序员犯打字错误的可能性更小……所需的类型转换越少,潜在的错误源就越少!一旦您确定列表只能包含Fiddle
对象 ( List<Fiddle>
),编译器将保留此信息并防止您必须将该列表中的每个项目类型转换为某种类型。(您仍然可以将列表项转换为Frobble
,但是既然编译器让您知道该项目是一个Fiddle
!,为什么要这样做?)
我发现泛型极大地减少了类型转换的需求,所以大量类型转换的存在——尤其是当你总是转换为相同的类型时——可能表明应该使用泛型。
让编译器保留尽可能多的类型信息是一件好事,因为可以更早地发现类型错误(在编译时而不是在运行时)。
java.lang.Object
类型的替代品:在泛型之前,如果你想编写一个适用于任何类型的方法,你可以使用java.lang.Object
超类型,因为每个类都派生自它。
泛型还允许您编写适用于任何类型的方法,但不会强迫您或编译器丢弃已知的类型信息——这正是您将对象转换为Object
类型时发生的情况。因此,频繁使用该Object
类型可能是泛型可能适用的另一个指标。
何时涉及收藏?
为什么泛型似乎特别适合集合?因为,根据上述推理,集合很少允许包含任何类型的对象。如果是这样,那么该Object
类型将是合适的,因为它不会对集合施加任何限制。但是,通常,您希望集合中的所有项目(至少)是一个Frobble
(或某种其他类型),如果您让编译器知道它会有所帮助。泛型是如何做到这一点的方式。
关系是否是类的组合/聚合?
您已链接到另一个问题,该问题询问是否应将属性设为通用class Person
的.car
class Person<T extends ICar>
在这种情况下,这取决于您的程序是否需要区分本田人和欧宝人。通过使这样的Person
类通用,您基本上介绍了不同类型的人的可能性。如果这实际上解决了您的代码中的问题,那么就去做吧。但是,如果它只是引入了障碍和困难,那么请抵制这种冲动并留在您的非泛型Person
类中。
侧节点:请记住,您不必使整个类通用;您只能使一些特定的方法通用。至少在 .NET 生态系统中,建议尽可能将泛型保持为“本地”,即当仅使方法泛型就足够时,不要将类变成泛型。
当满足以下三个条件时,我发现自己使用泛型:
<T extends Bar>
)。通常,当满足这些标准时,会Collection
涉及某种类型,但不一定。
在我看来,第二个陈述(什么时候不使用它们)是正确的。
何时不使用泛型:当强类型过于严格时(通常是泛型中的泛型)。在某些情况下,您希望确保组件之间的松散耦合,重点是“将您想要的发送给我,API 会以某种方式处理它”,而不是使用某种访问者,而不是使用某种通用类型指定完整的具体 API .
何时应该:如果没有,则必须将变量强制转换为某种类型(甚至您可能不得不猜测或使用 instanceof)...
只是一个旁注:每个结构化类型都是某种集合......