Java 泛型(模板)专用化可能(用特定类型覆盖模板类型)

2022-09-01 14:37:52

我想知道在Java中专门化泛型类型的选项是什么,即在模板化类中为某些类型提供特定的覆盖。

在我的情况下,我是一个泛型类(类型T),通常返回null,但返回“”(空字符串),当T是字符串类型时,或0(零)当它是整数类型时,依此类推。

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

例如:

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()方法中检查实例,例如T get(T t) { if (t instanceof String) return “”;if (t instanceof Integer) 返回 0;else 返回 null;}

然而,我被教导要避免实例化,并在可能的情况下使用多态性。


答案 1

考虑到所有因素,问题中提到的StringBar方法似乎是唯一的出路。

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

答案 2

在这方面,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>;
}

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


推荐