我想知道在Java中专门化泛型类型的选项是什么,即在模板化的类中对某些类型进行特定的覆盖。
在我的情况下,我是一个泛型类(类型为T)通常返回null,但返回“”(空字符串),当T是String类型时,或者当它是Integer类型时返回0(零)等
仅提供方法的特定于类型的重载会产生“方法不明确”错误:
e.g:
public class Hacking {
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
Bar<String> barString = new Bar<String>();
// OK, returns null
System.out.println(barInt.get(new Integer(4)));
// ERROR: The method get(String) is ambiguous for the type Bar<String>
System.out.println(barString.get(new String("foo")));
}
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
}
是使用特定类型对泛型类进行子类化的唯一选项(请参阅以下示例中的StringBar?
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
StringBar barString2 = new StringBar();
// OK, returns null
System.out.println(barInt.get());
// OK, returns ""
System.out.println(barString2.get());
}
public static class Bar<T> {
public T get() {
return null;
}
}
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
}
这是唯一的方法,必须为我想要专门化的每个类型创建一个子类而不是Bar类中的get()重载,这有点痛苦。
我猜我可以检查Bar.get()方法中的instanceof,例如 T get(T t){ if(t instanceof String)返回“”; if(t instanceof Integer)返回0; else返回null; }
然而,我被教会在可能的情况下避免使用instanceof并使用多态。
答案 0 :(得分:12)
考虑到所有事情,共识似乎是问题中提到的StringBar方法方法是唯一的方法。
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
答案 1 :(得分:4)
Java中的泛型不是专业化的。它们是为概括而制作的!如果你想专门研究某些类型,你应该通过子类专门化。
然而,您通常不需要以专门的方式做某事。您的StringBar示例有点人为,因为您可以这样做:
public class Bar<T> {
private final T value;
public T get() {
return value;
}
}
我不明白为什么你需要在这里专门设置一个字符串。
答案 2 :(得分:4)
编译器实际上是正确的,因为以下代码在编译时是编译时检查的(Bar<String> barString = new Bar<String>();
),来自
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
到
public static class Bar<String> {
public String get(String x) {
return null;
}
public String get(String x) {
return "";
}
}
并且不明确,因为你不能有2个相同的方法,它们具有相同的返回类型和相同的参数参数。
请参阅Jon Skeet的解释:
您可以创建Bar<T>
的子类并创建StringBar
(请注意我删除了static
关键字)并覆盖get()
方法。
public class BarString extends Bar<String> {
@Override
public String get(String x) {
return "";
}
}
答案 3 :(得分:4)
Java中的泛型在这方面与C ++中的模板非常不同。如C ++所能做的那样,不可能编写特定版本的泛型类来为特定情况做一些不同的事情。在运行时也无法确定T是什么 - 这是因为该信息未传递到字节代码(目标代码)中,因此在运行时甚至不存在。这是由于所谓的“类型擦除”。
BarString和BarInt显然是这样做的方法,但你可以做出改进。例如,您可以编写一个通用Bar来覆盖常见情况,然后编写专门的BarString和BarInt来实现特殊情况。确保只能通过工厂创建实例,工厂需要处理对象的类:
class Bar<T> {
class BarString extends Bar<String> {
// specialist code goes here
}
static Bar<T> createBar(Class<T> clazz) {
if (clazz==String.class) {
return new BarString();
} else {
return new Bar<T>;
}
那可能无法编译,但我没有时间计算出确切的语法。它确实说明了这一原则。