(这可能是重复的,但我找不到它 - 随意指出来)
考虑以下Java类:
public class A<T0, T1> {
public A(T0 t0, T1 t1) {
...
}
}
使用new A<Integer, String>(1, "X")
。
现在假设此类的大多数实例都有String
作为第二个类型参数T1
,并且构造函数调用中使用的此类型的对象也非常标准。
如果 A
没有使用泛型,那么常见的扩展名将是没有第二个参数的额外构造函数:
public class A {
public A(int t0, String t1) {
...
}
public A(int t0) {
this(t0, new String("X"));
}
}
不幸的是,对于使用泛型的类来说,这似乎是不可能的 - 至少在没有强制转换的情况下:
public A(T0 t0) {
this(t0, (T1)(...));
}
原因?虽然这个构造函数只接受一个参数,但它仍然使用两个类型的参数,并且没有办法知道先验那个类型T1
的用户类供应将与构造函数中使用的默认值兼容。
稍微优雅的解决方案涉及使用子类:
public class B<T0> extends A<T0, String> {
...
}
但是这种方法强制了类层次结构中的另一个分支,而另一个类文件的主要是boilerplate code。
有没有办法声明一个强制一个或多个类型参数为特定类型的构造函数?与使用子类具有相同效果的东西,但没有麻烦?
我对仿制药和/或我的设计的理解是否存在根本错误?或者这是一个有效的问题吗?
答案 0 :(得分:6)
最简单的方法就是添加静态创建方法。
public static <T0> A<T0,String> newThing(T0 t0) {
return new A<T0,String>(t0, "X");
}
(或许选择适合特定用途的名称。通常不需要new String("...")
。)
从Java SE 7开始,您可以使用钻石:
A<Thing,String> a = new A<>(thing);
答案 1 :(得分:2)
据我所知,你想要第二个构造函数(如果被调用)会强制泛型类型T1为String。
但是,在调用构造函数之前指定泛型。
第二个构造函数,如果有效,可以允许某人执行此操作:
B<Integer, Integer> b = new B<Integer, Integer>(5);
这里的错误是你在调用构造函数之前已经将第二个泛型类型指定为Integer。然后构造函数理论上将第二个泛型类型指定为String。这就是为什么我认为这是不允许的。
答案 2 :(得分:1)
“大多数实例”是根本问题。
T1是否是参数化类型。单参数构造函数假设两者。这就是问题所在。
子类解决方案通过使所有实例满足T1 = String来解决问题。
命名构造函数/工厂方法也可以通过确保T1 = String来解决问题。
public static <T0> A<T0,String> makeA( T0 t0 ) {
return new A<T0,String>( t0, "foo" );
}
答案 3 :(得分:1)
您可以限定泛型类型,即
A<T0, T1 super MyDefaultType> {
public A(T0 t0) {
this(t0, new MyDefaultType());
}
}
您无法使用T1 extends MyDefaultType
,因为如果您定义子类,MyDefaultType
实例将与T1
的类型兼容。
答案 4 :(得分:0)
有没有办法声明一个强制一个或多个类型参数为特定类型的构造函数?与使用子类具有相同效果的东西,但没有麻烦?
我认为这是不可能的。想想这个。 Developer定义了可以是通用的类,即在创建对象期间定义参数的类型。开发人员如何定义强制用户使用特定类型参数的构造函数?
编辑: 如果需要,您必须创建工厂或工厂方法,以使用预定义的参数类型创建此类的实例。
答案 5 :(得分:0)
它的子类。据我所知,这是OOP的一大特色。好好享受。磁盘空间很便宜。
如果这是将来维护代码的问题,请考虑将原始类抽象化,并创建两个子类(一个使用双通用构造函数,另一个使用单个。