Java 泛型构造函数的用例是什么?

Java 泛型构造函数的用例是什么?,java,generics,constructor,Java,Generics,Constructor,考虑类Foo(为了清楚起见,它不是泛型类)的以下构造函数: 当然,泛型不仅仅是关于返回类型的类型安全性。构造函数可能只想约束传入的参数类型。但是,上述推理仍然适用于有界类型参数: public <N extends Number> Foo(N number) { } public Foo(Number number) { } //same thing publicfoo(N个数){ 公共Foo(Number){}//同样的事情 即使有边界的嵌套类型参数也使用通配符处理: pub

考虑类
Foo
(为了清楚起见,它不是泛型类)的以下构造函数:

当然,泛型不仅仅是关于返回类型的类型安全性。构造函数可能只想约束传入的参数类型。但是,上述推理仍然适用于有界类型参数:

public <N extends Number> Foo(N number) { }

public Foo(Number number) { } //same thing
publicfoo(N个数){
公共Foo(Number){}//同样的事情
即使有边界的嵌套类型参数也使用通配符处理:

public <N extends Number, L extends List<N>> Foo(L numList) { }

public Foo(List<? extends Number> numList) { } //same thing
publicfoo(L numList){

public Foo(List我能想到的一个用例是,当您想要将一个构造函数参数约束为多个类型时。只有通用语法允许您声明一个构造函数,它使用的是一个
列表
编号
也实现了
随机访问

public <L extends List<? extends Number> & RandomAccess> Foo(L raNumList) { }

...

Foo f1 = new Foo(new ArrayList<Integer>());
Foo f2 = new Foo(new LinkedList<Integer>()); //compiler error

public我能想到的一件事是,您可以确保在多个参数之间以相同的方式实现边界

以一个显然愚蠢、做作但有效的构造函数为例,它将列表从源复制到目标:

public <T> Foo (List<T> listA, List<T> listB) {
    listA.addAll(listB);
}
public Foo(列表A、列表B){
listA.addAll(listB);
}

在这里使用通配符会很快变得非常讨厌,而且可能不会做任何你想做的事情。禁止通配符也是一种完全任意的限制。因此,语言规范允许使用通配符对我来说是有意义的。

这里有一个可能的通配符,它是根据函数式编程改编的。假设我们有一个
类型,它有一些内部状态,反复生成新元素,直到它返回
null
。外部调用方不关心流类型的内部状态类型是什么,因此您可能会得到如下结果

class Stream<E> {
  <S> Stream(S initialState, StepFunction<E, S> stepFun) {
    ...
  }
}
类流{
流(S初始状态,stepFun函数){
...
}
}

接收者不必知道内部状态类型是什么。

您可以对构造函数参数实施某些约束。例如,以下代码需要两个实现接口InterfaceA和InterfaceB的参数

<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) {

}
Foo(t1,t2){
}

主要用途是确保在多个参数之间满足类型约束。下面是一个示例,它将一组组件按正确顺序放置在装配线上:

public <T> AssemblyLine(T[] starting, List<T> components) {
  T[] a = components.toArray(starting);
  Arrays.sort(a);
  this.conveyorBelt.add(a);
}
公共装配线(T[]开始,列出组件){
T[]a=组件。toArray(启动);
数组。排序(a);
本条。输送带。添加(a);
}

这里的
确保
T[]
List
保持相同的类型
T
,而不是(比如),
Integer[]
List

+1我忘记了泛型数组和传递实例的必要性,等等-很好(我认为有一个输入错误-应该是
组件。toArray
)+1,这是一个很好的例子,尽管它有点欺骗,因为OP特别指出封闭类型不是泛型的。(
Stream
将是泛型的。)@JohnFeminella-我只是说我的特定示例
Foo
不是泛型的,只是为了避免混淆。我不是说这是对答案的限制。我理解OP的问题是询问使用非类类型的泛型参数的构造函数。作为参考,Haskell程序员会立即意识到这一点存在量化
S
;直接启发是。我不认为这个例子是正确的。为了让这个类像你描述的那样工作并且是类型安全的,它必须存储一个“状态”涉及类型
S
的数据成员。因此,
S
必须是类的类型参数。或者为了与前泛型代码向后兼容,其中
Foo
采用了
对象
,但现在您需要更专业的东西。
Foo(T obj)
/我并不认为这一切都很普遍。或者在body中使用
T
Foo(List ts){T t0=ts.get(0);ts.set(0,ts.get(1));ts.set(1,t0);}
。好的,这不是一个令人信服的例子。
class Stream<E> {
  <S> Stream(S initialState, StepFunction<E, S> stepFun) {
    ...
  }
}
<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) {

}
public <T> AssemblyLine(T[] starting, List<T> components) {
  T[] a = components.toArray(starting);
  Arrays.sort(a);
  this.conveyorBelt.add(a);
}