众所周知,通过使用类型参数,您可以在Java中使用泛型类:
class Foo<T> {
T tee;
Foo(T tee) {
this.tee = tee;
}
}
但是你也可以使用泛型构造函数,这意味着显式接收它们自己的泛型类型参数的构造函数,例如:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
我正在努力理解用例。这个功能让我做了什么?
答案 0 :(得分:23)
我正在考虑的用例可能是某些人想要一个继承自2种类型的Object。例如。实现2 interfaces
:
public class Foo {
public <T extends Bar & Baz> Foo(T barAndBaz){
barAndBaz.barMethod();
barAndBaz.bazMethod();
}
}
虽然我从未在生产中使用它。
答案 1 :(得分:19)
在您提供的示例中,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!
}
}
请注意,该类已经使用了不同的泛型类型;这允许您在类定义中使用单独的,不相关的泛型类型。
当然,我从来没有使用过这样的东西,而且我从来没有看到它在使用过,但它是可能的!
答案 2 :(得分:15)
这个功能让我做了什么?
至少有三它可以让你做的两件事,你不能这样做:
表达参数类型之间的关系,例如:
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.
// ...
}
}
&LT;抽出&GT;
正如@Lino首先观察到的那样,它允许你表达参数必须与两个或更多不相关类型的组合兼容(当所有但最多只有一个是接口类型时才有意义)。请参阅Lino的答案。
答案 3 :(得分:10)
实际上,这个构造函数
class Bar {
<U> Bar(U you) {
// Why!?
}
}
就像generic method一样。如果你有这样的多个构造函数参数会更有意义:
class Bar {
<U> Bar(U you, List<U> me) {
// Why!?
}
}
然后你可以强制执行约束,它们与编译器有相同的时间。不使U成为全班的通用。
答案 4 :(得分:8)
因为未绑定的泛型类型会删除到Object
,所以它与在构造函数中传递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
是相同的(并具有相同的实用程序)。