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

时间:2010-10-21 13:54:22

标签: java generics

我想知道在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并使用多态。

4 个答案:

答案 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>;
}

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