通用构造函数在Java中的作用是什么?

0xb*_*7ed 33 java generics constructor

众所周知,通过使用类型参数,您可以在Java中使用泛型类:

class Foo<T> {
    T tee;
    Foo(T tee) {
        this.tee = tee;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是您也可以使用泛型构造函数,这意味着构造函数显式接收它们自己的泛型类型参数,例如:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}
Run Code Online (Sandbox Code Playgroud)

我很难理解用例.这个功能让我做了什么?

Lin*_*ica 23

我正在考虑的用例可能是某些人想要一个继承自2种类型的Object.实施2 interfaces:

public class Foo {

    public <T extends Bar & Baz> Foo(T barAndBaz){
        barAndBaz.barMethod();
        barAndBaz.bazMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我从未在生产中使用它.


Jac*_* G. 19

在你提供的示例中很明显,它U在类的构造函数中没有任何作用,因为它Object在运行时实际上变成了一个:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,让我们说我希望我的构造函数只接受扩展其他类或接口的类型,如下所示:

class Foo<T extends Baz> {
    <U extends Bar> Foo(U u) {
        // I must be a Bar!
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,该类已经使用了不同的泛型类型; 这允许您对类定义使用单独的,不相关的泛型类型.

当然,我从来没有使用过这样的东西,我从未见过它,但它有可能!

  • 如果您需要知道的是'u`是一个'Bar`,那么简单地做'Foo(Bar u){}`是不是更好的做法?我完全同意你对'Baz`后代的泛型的想法 - 一个很好的例子是`<T extends Comparable>`用于基于比较的有序数据结构,比如搜索树 (21认同)
  • `<U extends Bar&Baz> Foo(U u)`其中Bar和Baz不相关(例如两个接口,构造函数都需要它们). (6认同)

Joh*_*ger 15

这个功能让我做了什么?

它至少有件让你做的事情,否则你无法做到:

  1. 表达参数类型之间的关系,例如:

    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.
            // ...
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. <抽出>

  3. 正如@Lino首先观察到的那样,它允许你表达参数必须与两个或更多不相关类型的组合兼容(当所有但最多只有一个是接口类型时才有意义).请参阅Lino的答案.


keu*_*leJ 10

实际上,这个构造函数

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}
Run Code Online (Sandbox Code Playgroud)

就像一个通用的方法.如果你有这样的多个构造函数参数会更有意义:

class Bar {
    <U> Bar(U you, List<U> me) {
        // Why!?
    }
} 
Run Code Online (Sandbox Code Playgroud)

然后你可以强制执行约束,它们与编译器具有相同的时间.不使U成为全班的通用.

  • 编译器可以决定将Object作为U插入来解决问题,在什么情况下你仍然可以传递一个int和一个字符串对象. (4认同)
  • 但请注意,除非在调用示例构造函数时明确指定type参数,否则Java可以将`U`推断为`Object`,因此不会产生任何限制. (4认同)

Mak*_*oto 8

因为未绑定的泛型类型会删除Object,所以它与传递Object构造函数相同:

public class Foo {
    Object o;

    public Foo(Object o) {
        this.o = o;
    }
}
Run Code Online (Sandbox Code Playgroud)

......但是就像传递空白一样Object,除非你做得很聪明,否则这几乎没有实际价值.

如果您传入绑定泛型,您会看到好处并获胜,这意味着您实际上可以保证您关注的类型.

public class Foo<T extends Collection<?>> {
    T collection;
    public Foo(T collection) {
        this.collection = collection;
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上,这更多的是灵活性,而不是革命性的东西.如果您希望灵活地传递特定类别的类型,那么您可以在此处执行此操作.如果你不这样做,那么标准类就没有错.它仅仅是为了您的方便,因为类型擦除仍然是一个东西,未绑定的泛型与传递相同(并具有相同的实用程序)Object.

  • OP似乎专注于他的类"Bar"中的泛型构造函数,主要是为了对比而提出了泛型类`Foo`.虽然这个答案中的所有内容都是正确的,但我很难看到它如何响应泛型构造函数问题. (2认同)