【问题标题】:Generic factory function for generic type泛型类型的泛型工厂函数
【发布时间】:2018-05-14 15:42:59
【问题描述】:

我知道这个问题与 java parameterized generic static factory.

到目前为止,我还没有找到这个确切的案例,也无法弄清楚我想做的事情是否可以完成。所以,假设这个几乎是最小的例子:

public class Test {
  public static interface Interface<T, P> {
    T get(P param);
  }

  public static class StringIntInterface implements Interface<String, Integer> {
    public String get(Integer param) {
      String[] options = new String[] { "hello", "cruel", "world" };
      int p = param > 0 ? param : -param;
      return options[p % 3];
    }
  }

  public static class IntStringInterface implements Interface<Integer, String> { 
    public Integer get(String param) {
      return param.length();
    }
  }

  public static class InterfaceProvider {
    public Interface<?, ?> getInterface(String name) {
      if (name.equals("int")) {
        return new StringIntInterface();
      } else if (name.equals("string")) {
        return new IntStringInterface();
      }
      return null;
    }
  }

  public static void main(String... args) {
    InterfaceProvider ip = new InterfaceProvider();
    StringIntInterface si = (StringIntInterface)ip.getInterface("int");
    IntStringInterface is = (IntStringInterface)ip.getInterface("string");
    System.out.println(si.get(5));
    System.out.println(is.get("a somewhat long string, whatever"));
  }
}

这是迄今为止我编译和按预期工作的唯一版本,而且有趣的是(对我而言)没有未经检查的转换警告......

我想我想在这里做什么很清楚,但是有没有办法摆脱 Test::main()InterfaceProvider::getInterface() 用法中的强制转换?我尝试了各种方法使InterfaceProvider::getInterface() 成为通用方法,所有这些都会导致编译错误。到目前为止,那些尝试过的签名是:

public <R, P, T extends Interface<R, P>> T getInterface(String name);
public <R, P, T extends Interface<R, P>> T getInterface(String name, Class<R> retType, Class<P> paramType);
public <T extends Interface<?, ?>> T getInterface(String name);

因为我希望 Interface 的参数 TP 没有任何界限,并且只想为 Interface 的任何实现实例化一个 InterfaceProvider 我没有选项将任何类型参数移动到 InterfaceProvider 类...

有什么想法吗?或者这根本不可能?

【问题讨论】:

  • 您有没有想过在InterfaceProvider 上使用2 个单独的方法,每个接口1 个?
  • 遗憾的是,这不是一个选择。我在编写一个系统时遇到了这个问题,其中接口的实现由用户在运行时提供,由类名动态加载。 T 和 P 很可能最终会以相同的方式提供。

标签: java generics factory-method


【解决方案1】:

您不应在main 中使用StringIntInterfaceIntStringInterface。接口是定义一个规范,让用户不需要关心实现。如果需要知道具体实现StringIntInterface,为什么需要工厂?所以应该是

Interface<String, Integer> si = (Interface<String, Integer>) ip.getInterface("int");
Interface<Integer, String> is = (Interface<Integer, String>)ip.getInterface("string");

现在你们所有尝试的签名都可以工作了

public <R, P, T extends Interface<R, P>> T getInterface(String name);
Interface<String, Integer> si = ip.getInterface("int");
Interface<Integer, String> is = ip.getInterface("string");

但请注意,尽管它有效(您不需要进行显式转换),但一切都不会改变。它仍然不是类型安全的。

【讨论】:

  • 感谢您的回答,但很遗憾,它不起作用。 javac返回的错误:Test.java:23: error: incompatible types: StringIntInterface cannot be convert to T return new StringIntInterface(); ^ 第 25 行相同 (new IntStringInterface())
  • @tjanu 返回时请加(T)return (T) new IntStringInterface();
  • 谢谢,这确实修复了它并且类型安全足以满足我的需要(当我在InterfaceProvider::getInterface() 中交换返回语句时抛出 ClassCastException),这就是我在这方面需要的所有“安全性”。当然,未经检查的演员阵容有点丑陋,但我想在这种情况下也无济于事。
  • @tjanu 如果它真的解决了你的问题,请接受它:)
  • 抱歉,忘记了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多