class Foo<T> {
T tee;
Foo(T tee) {
this.tee = tee;
}
}
但你也可以拥有通用的构造函数,即显式接收自己的通用类型参数的构造函数,例如:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
我很难理解使用案例。这个功能让我能做什么?
class Foo<T> {
T tee;
Foo(T tee) {
this.tee = tee;
}
}
但你也可以拥有通用的构造函数,即显式接收自己的通用类型参数的构造函数,例如:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
我正在考虑的使用案例可能是有人想要一个继承自2个类型的对象。例如,实现了2个接口:
public class Foo {
public <T extends Bar & Baz> Foo(T barAndBaz){
barAndBaz.barMethod();
barAndBaz.bazMethod();
}
}
虽然我从未在生产环境中使用过它。
interface BarBaz extends Bar, Baz
或类似的方式解决这个问题,但这可能是一种更好的表达方式。但有趣的是,它更加“弱类型”,因为没有运行时类型。 - 0xbe5077ed从您提供的示例中可以明显看出,在类的构造函数中,U
并没有扮演任何角色,因为在运行时它实际上变成了一个Object
:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
假设我想让构造函数只接受继承自其他类或接口的类型,如下所示:
class Foo<T extends Baz> {
<U extends Bar> Foo(U u) {
// I must be a Bar!
}
}
u
是一个Bar
,那么简单地使用Foo(Bar u) {}
不是更好的做法吗?我完全赞同你对于泛型化Baz
后代的想法 - 一个很好的例子是针对基于比较排序的数据结构,如搜索树的 <T extends Comparable>
。 - musicman523<U extends Bar & Baz> Foo(U u)
表示泛型方法 Foo
接受一个类型参数 U
,该类型参数必须同时实现 Bar
和 Baz
两个接口(即 U
必须是 Bar
和 Baz
的交集)。注意,Bar
和 Baz
之间并没有继承关系(例如它们是两个接口),但在这个方法中都被要求。 - Draco18s no longer trusts SEBar
和 Baz
是接口,您仍然会使用 extends
而不是 implements
吗? - musicman523implements
不是适当的关键字,所以无法编译。 - Jacob G.这个功能让我可以做什么?
至少有两件事情是这个功能可以让你做到,否则你是无法完成的:
express relationships between the types of the arguments, for example:
class Bar {
<T> Bar(T object, Class<T> type) {
// 'type' must represent a class to which 'object' is assignable,
// albeit not necessarily 'object''s exact class.
// ...
}
}
<withdrawn>
As @Lino observed first, it lets you express that arguments must be compatible with a combination of two or more unrelated types (which can make sense when all but at most one are interface types). See Lino's answer for an example.
T
推断为 Object
,从而让任何东西通过吗? - user2357112Object
类型。当存在其他约束条件时,设置下限更加有趣。 - John Bollinger实际上,这个构造函数
class Bar {
<U> Bar(U you) {
// Why!?
}
}
就像泛型方法一样。如果您有多个构造函数参数,那么这将更加有意义:
class Bar {
<U> Bar(U you, List<U> me) {
// Why!?
}
}
那么您可以强制执行约束条件,使其与编译器具有相同的时间,而不将U作为整个类的通用类型。
U
为Object
,从而不会加限制。 - John Bollinger<init>
的通用方法。但对于一个通用方法,在实践中通常处理的是一个static
方法,因为对于主要的实例方法,它们通常可以使用从类中“继承”的“通用性”来完成所需的操作。我想知道你可能会用通用构造函数做什么,因为构造函数主要初始化类状态,很难想象在没有可用于类的通用维度的情况下设置类状态的场景... - 0xbe5077edjavac
与Bar(Object you,Object me)
完全相同。因此,泛型参数是多余的,并且会稍微令人困惑。而许多使用泛型参数实际上表达了可以在编译时静态验证的有意义的约束条件。 - 0xbe5077edObject
,所以这与在构造函数中传递 Object
是一样的:public class Foo {
Object o;
public Foo(Object o) {
this.o = o;
}
}
......但是,就像传递一个空的Object
一样,除非你做了一些聪明的事情,否则这几乎没有实际价值。
如果您传入绑定的泛型,则可以看到收益和优势,这意味着您实际上可以确保关心的类型。
public class Foo<T extends Collection<?>> {
T collection;
public Foo(T collection) {
this.collection = collection;
}
}
实际上,这更多的是关于灵活性而不是革命性的东西。如果您想要传递特定类别类型的灵活性,则在此处有这样的能力。如果您不需要,则使用标准类没有问题。这仅为您方便而存在,并且由于类型擦除仍然存在,未绑定的泛型与传递 Object
相同(并具有相同的效用)。
Bar
中的通用构造函数,主要是为了对比而呈现通用类Foo
。尽管此答案中的所有内容似乎都是正确的,但我很难看出它如何响应通用构造函数问题。 - John Bollinger
<U> Bar(U a, U b)
? - Henry