泛型构造函数在Java中的作用是什么?
众所周知,您可以使用类型参数在Java中创建泛型类:泛型构造函数在Java中的作用是什么?,java,generics,constructor,Java,Generics,Constructor,众所周知,您可以使用类型参数在Java中创建泛型类: class Foo<T> { T tee; Foo(T tee) { this.tee = tee; } } class-Foo{ T形三通; 傅(T-tee){ this.tee=tee; } } 但也可以有泛型构造函数,这意味着构造函数显式地接收自己的泛型类型参数,例如: class Bar { <U> Bar(U you) { // Why!?
class Foo<T> {
T tee;
Foo(T tee) {
this.tee = tee;
}
}
class-Foo{
T形三通;
傅(T-tee){
this.tee=tee;
}
}
但也可以有泛型构造函数,这意味着构造函数显式地接收自己的泛型类型参数,例如:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
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.
// ...
}
}
类栏{
酒吧(你){
//为什么!?
}
}
我正在努力理解这个用例。此功能允许我做什么?因为未绑定的泛型类型将擦除到
对象
,这与在构造函数中传递对象
相同:
public class Foo {
Object o;
public Foo(Object o) {
this.o = o;
}
}
…但就像传递一个空白的对象
,除非你做了一些聪明的事情,否则这没有什么实用价值
如果您传入绑定泛型,您将看到好处和收益,这意味着您实际上可以对所关心的类型进行保证
public class Foo<T extends Collection<?>> {
T collection;
public Foo(T collection) {
this.collection = collection;
}
}
public class Foo在您提供的示例中很明显,U
在类的构造函数中不起任何作用,因为它在运行时实际上变成了一个对象
:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
类栏{
酒吧(你){
//为什么!?
}
}
但假设我希望我的构造函数只接受扩展其他类或接口的类型,如下所示:
class Foo<T extends Baz> {
<U extends Bar> Foo(U u) {
// I must be a Bar!
}
}
class-Foo{
傅(U){
//我一定是酒吧!
}
}
请注意,该类已使用不同的泛型类型;这允许您使用与类定义无关的单独泛型类型
当然,我从来没有使用过这样的东西,也从来没有见过它在使用,但这是可能的 实际上,这个构造函数
class Bar {
<U> Bar(U you) {
// Why!?
}
}
类栏{
酒吧(你){
//为什么!?
}
}
就像是一只猫。如果您有多个构造函数参数(如下所示),则更有意义:
class Bar {
<U> Bar(U you, List<U> me) {
// Why!?
}
}
类栏{
酒吧(你,把我列出来){
//为什么!?
}
}
然后您可以强制执行约束,即它们与编译器具有相同的时间。没有使U成为整个类的泛型。我想到的用例可能是一些人想要一个从两种类型继承的对象。例如,实现2个接口
:
public class Foo {
public <T extends Bar & Baz> Foo(T barAndBaz){
barAndBaz.barMethod();
barAndBaz.bazMethod();
}
}
公共类Foo{
公共食品(T barAndBaz){
barAndBaz.barMethod();
barAndBaz.bazMethod();
}
}
虽然我从未在生产中使用过它
这个功能让我做什么
至少有三件两件事是它能让你做的,这是你无法做的:
表示参数类型之间的关系,例如:
class Bar {
<U> Bar(U you) {
// Why!?
}
}
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.
// ...
}
}
类栏{
条形图(T对象,类类型){
//“type”必须表示“object”可赋值的类,
//尽管不一定是“对象”的确切类别。
// ...
}
}
正如@Lino首先观察到的,它允许您表示参数必须与两个或多个不相关类型的组合兼容(当除最多一个之外的所有类型都是接口类型时,这是有意义的)。有关示例,请参见Lino的答案
可能在这样的情况下:Bar(U a,U b)
?这个例子没有太大帮助。但泛型可以帮助您在必须扩展另一种类型或是交叉类型时,根据参数建立契约。(例如)通用方法很有用。构造函数与方法类似。即使没有特别引人注目的用例,禁止泛型构造函数也比允许泛型构造函数更难。提示:如果你能做某件事,并不意味着你应该做。请参阅。您可以要求多个参数应用于一致类型。编译器可以决定将对象作为U插入以解决此问题,在这种情况下,您仍然可以传递int和string对象。但请注意,除非在调用示例构造函数时显式指定类型参数,Java可以推断U
为Object
,因此没有任何限制。我知道这就像一个泛型方法,实际上它是一个具有特殊名称的泛型方法,
。但是对于泛型方法,实际上通常处理的是静态
方法,因为对于main,实例方法通常可以使用它们从类“继承”的“泛型性”来完成它们需要的工作。我想知道你能用泛型构造函数做些什么,因为构造函数主要初始化类状态,很难想象你根据类不可用的泛型维度设置类状态的场景…@keuleJ,我想你误解了@JohnBollinger的意思。关键是javac
您的示例在编译时和运行时都与Bar(objectyou,objectme)
完全相同。因此,泛型参数是冗余的,并且有点容易引起混淆。然而,泛型参数有很多用途,它们实际上表示有意义的约束,可以在编译时进行静态验证。如果您需要知道的是u
是Bar
,那么简单地执行Foo(Bar u){}
不是更好的做法吗?我完全同意你的想法,即对Baz
的后代进行泛型-一个很好的例子是
用于基于比较的有序数据结构,例如搜索树Foo(U)
,其中Bar和Baz不相关(例如两个接口,这两个接口都是构造函数所要求的)。是的,如果Bar
和Baz
在您的示例中是接口,您还会使用extends
而不是implements
?@musicman523是的,因为implements
不是合适的关键字,OP似乎专注于类Bar
中的泛型构造函数,将泛型类Foo
主要用于对比。虽然这个答案中的所有内容似乎都是正确的,但我有tr