【问题标题】:Generics which admit parameters; or parameterizable generics允许参数的泛型;或可参数化的泛型
【发布时间】:2015-03-29 14:28:35
【问题描述】:

我正在玩一个有趣的架构。人们可以制作包含 StoredObjects 的 Store。存储可以支持由接口表示的不同操作(即 Get、Put、Print)。

这是高度简化的样子:

interface Put<Foo>{
   public void put(Foo f); 
}

class Store implements Put<Store.Obj<?>> {
    class Obj<T> {
        public T o;
    }
    @Override
    public void put(Obj<?> o) { }


}

public class Main {
        public static void main(String[] args){
                Store s = new Store();
                Store.Obj<String> o = s.new Obj<>();
                s.put(o);

        }
}

当我想实现类似的“get”方法时,问题就出现了。理想情况下,我想要一个如下所示的界面:

interface Get<Foo> {
    public <T> T get(Foo<T> f);
}

显然,这是畸形的 java.lang.是否有一些语法(或技巧)可以用来完成它的目的?实际上,我不想将常量类型指定为泛型参数,而是想将可参数化类型指定为泛型参数(然后它本身将在 get 方法中参数化)。是的,这归结为 java 没有的更高种类的类型;如此疯狂丑陋的 hack 非常受欢迎!

由于其他设计限制而无法使用的常见解决方案:

  • 将 get/put/etc 操作移到内部 Obj 类中
  • 创建Store.Obj&lt;T&gt; 的一些超类型并指定接受该超类型的接口,而不是泛型参数。

【问题讨论】:

  • 我不确定我是否理解这个问题。你想达到什么目的?也许您想要 之类的东西?
  • 不是真的,不; Java 的类型系统不支持更高种类的类型,这是您要查找的术语。
  • @LouisWasserman 太糟糕了。我来自 C++ 领域,它(超级偶然)实际上确实有这些更高种类的类型。

标签: java generics nested-generics


【解决方案1】:

你需要一些方法来从你的 Obj 中取出 T。我们称其为 Getter

interface Getter<O, I> {
    I get(O outer); // get the "inner" value out of the "outer" object
}

现在您可以为您的 Obj 类实现一个 getter:

class ObjTGetter<T> implements Getter<Obj<T>, T> {
    public T get(Obj<T> o) { return o.o; }
}

现在您的Store 构造函数还必须包含Getter 参数,因此您可以使用它来实现get。然后您的 Store 类变为:

class Store<O, I> implements Put<O>, Get<O, I> {
    private Getter<O, I> getter;
    public void put(O o) { … }
    public I get(O o) { … }
}

但是到那时你也可以摆脱你的Store,直接使用getter。

【讨论】:

    【解决方案2】:

    我想我们可以从一开始就忘记更高种类的类型,并且您知道您的建议是不可能的。

    这不是您可能想要的解决方案,但这是我在这个问题上的最佳短板。

    由于我们无法创建新的参数类型,因此我们将不得不求助于创建新的参数值。

    首先,我们必须声明Foo 是一个泛型类型。事实上,Java 8 中有一种更好的类型:Supplier&lt;T&gt;

    interface Supplier<T> {
      T get()
    }
    

    现在,假设我必须使用这种类型的值:

    Supplier<String> s = () -> "Hello";
    Supplier<Integer> i = () -> 42;
    

    好吧,既然我们没有已经建立的更高种类的类型,那么我们的Get 接口将不得不在编译时与一些泛型类型相结合:

    interface Get<S, F extends Supplier<S>> {
        public S get(Supplier<S> foo);
    }
    

    问题显然是,对于Supplier&lt;T&gt; 的每种可能类型 T,您都需要多个 Get 的实例/值,因此我们的值会爆炸式增长:

    Get<String, Supplier<String>> f = Supplier::get;
    Get<Integer, Supplier<Integer>> g = Supplier::get;
    

    然后我们可以做

    String m = f.get(); //yield "Hello"
    Integer n = g.get(); //yields 42
    

    供应商几乎可以包含您想要的任何内容,但我认为我们无法避免定义多个 Get 实例。

    【讨论】:

      猜你喜欢
      • 2015-04-28
      • 2021-08-19
      • 1970-01-01
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多