可能的Javagenerics(模板)专业化(覆盖具有特定类型的模板类型)

我想知道在Java中专门化generics类型的选项是什么,即在模板化的类中对某些类型进行特定的覆盖。

在我的例子中,我是一个通用类(类型为T)通常返回null,但返回“”(空字符串),当T是String类型时,或者当它是Integer类型时返回0(零)等。

仅提供方法的类型特定重载会产生“方法不明确”错误:

例如:

public class Hacking { public static void main(String[] args) { Bar barInt = new Bar(); Bar barString = new Bar(); // OK, returns null System.out.println(barInt.get(new Integer(4))); // ERROR: The method get(String) is ambiguous for the type Bar System.out.println(barString.get(new String("foo"))); } public static class Bar { public T get(T x) { return null; } public String get(String x) { return ""; } } } 

是使用特定类型子类化generics类的唯一选项(请参阅以下示例中的StringBar?

  public static void main(String[] args) { Bar barInt = new Bar(); StringBar barString2 = new StringBar(); // OK, returns null System.out.println(barInt.get()); // OK, returns "" System.out.println(barString2.get()); } public static class Bar { public T get() { return null; } } public static class StringBar extends Bar { public String get() { return ""; } } } 

这是唯一的方法,必须为我想要专门化的每个类型创建子类而不是Bar类中的get()重载,这有点痛苦。

我猜我可以检查Bar.get()方法中的instanceof,例如T get(T t){if(t instanceof String)return“”; if(t instanceof Integer)返回0; else返回null; }

然而,我被教导要尽可能避免使用instanceof并使用多态。

考虑到所有事情,共识似乎是问题中提到的StringBar方法方法是唯一的方法。

  public static class StringBar extends Bar { public String get() { return ""; } } 

编译器实际上是正确的,因为以下代码在编译时是编译时检查的( Bar barString = new Bar(); ),来自

 public static class Bar { public T get(T x) { return null; } public String get(String x) { return ""; } } 

 public static class Bar { public String get(String x) { return null; } public String get(String x) { return ""; } } 

并且是不明确的,因为你不能有2个相同的方法具有相同的返回类型和相同的参数参数。

请参阅Jon Skeet的解释:

  • 在java中擦除generics的概念是什么?
  • Java Generics – 类型删除 – 何时以及发生了什么?

你可以StringBar Bar并创建StringBar (注意我删除了static关键字)并覆盖了get()方法。

 public class BarString extends Bar { @Override public String get(String x) { return ""; } } 

在这方面,Java中的generics与C ++中的模板非常不同。 如C ++所能做的那样,不可能编写特定版本的generics类来为特定情况做一些不同的事情。 在运行时也无法确定T是什么 – 这是因为该信息未传递到字节代码(目标代码)中,因此在运行时甚至不存在。 这是由于所谓的“类型擦除”。

BarString和BarInt是显而易见的方法,但你可以做出改进。 例如,您可以编写一个通用Bar来覆盖常见的情况,然后编写专门的BarString和BarInt来实现特殊情况。 确保只能通过工厂创建实例,工厂接受要处理的对象的

 class Bar { class BarString extends Bar { // specialist code goes here } static Bar createBar(Class clazz) { if (clazz==String.class) { return new BarString(); } else { return new Bar; } 

这可能不会编译,但我没有时间计算出确切的语法。 它确实说明了原则。

Java中的generics不是专门化的。 它们是为了概括而制造的! 如果你想专门研究某些类型,你应该通过子类专门化。

但是,您通常不需要以专门的方式做某事。 您的StringBar示例有点人为,因为您可以这样做:

 public class Bar { private final T value; public T get() { return value; } } 

我不明白为什么你需要在这里专门设置一个String。