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);
}