允许参数的泛型;或可参数化的泛型

时间:2015-01-30 06:28:38

标签: java generics nested-generics

我有一个有趣的建筑我正在玩。人们可以制作包含StoredObjects的商店。商店可以支持由界面表示的不同操作(即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。是否有一些语法(或黑客)可以用来实现这意味着什么?实际上,我不想将常量类型指定为泛型参数,而是将可参数化类型指定为泛型参数(然后将在get方法中对其进行参数化)。是的,这归结为更高级的类型,java没有;如此疯狂 - 丑陋的黑客不仅仅是欢迎!

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

  • 将get / put / etc操作移动到内部Obj
  • 创建一些Store.Obj<T>的超类型并指定接受它的接口,而不是通用参数。

2 个答案:

答案 0 :(得分:0)

你需要一些方法让你的Obj离开。我们称之为 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。您的商店类将成为:

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。

答案 1 :(得分:0)

我想我们可以从一开始就忘记高等级的类型,你知道你的建议是不可能的。

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

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

首先,我们必须声明Foo是通用类型。事实上,Java 8中有一种更好的类型:Supplier<T>

interface Supplier<T> {
  T get()
}

现在,让我说我必须使用这种类型的值:

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

好吧,既然我们没有更高级的kinded类型,那么我们的Get接口必须在编译时与一些泛型类型相结合:

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

问题显然是,对于Get的每个可能类型T,您需要Supplier<T>的多个实例/值,因此我们有了大量的值:

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实例。