从单个构造函数参数中推断泛型类类型参数

时间:2016-05-10 11:05:17

标签: java generics constructor

我想要的是:

大多数情况下,泛型类将类似于TestBuilder<X, X>,这意味着T和O属于同一类型。因此我创建了两个不同的构造函数。我想做一些像new TestBuilder<>(...)这样的新调用(我在这里称<>为无效)。

以下4个构造函数示例存在:

1)工作构造函数调用

// Anonoumous, working
new TestBuilder<>(String.class, Integer.class)
    .withOnNext(new Action1<Integer>()
    {
        @Override
        public void call(Integer integer)
        {   
        }
});

// not anonoumous, classified, working
new TestBuilder<String, String>(String.class)
    .withOnNext(new Action1<String>()
    {
        @Override
        public void call(String string)
        {
        }
});

2)构造函数调用有问题或无法正常工作

// Anonoumous and working
// PROBLEM: withOnNext is called with Object instead of String
new TestBuilder<>(String.class)
    .withOnNext(new Action1<Object>()
    {
        @Override
        public void call(Object o)
        {
        }
});

// Anonoumous and NOT working
// this is what I want to work!
new TestBuilder<>(String.class)
    .withOnNext(new Action1<String>()
    {
        @Override
        public void call(String string)
        {
        }
});

问题

有没有办法让第4个构造函数工作?如果我只使用一个参数调用它,我不希望被强制给构造函数两个类,第二个泛型类应该在这种情况下从第一个继承“...而不是必须写new TestBuilder<String, String>(String.class)我想写new TestBuilder<>(String.class)或至少new TestBuilder<String>(String.class) ...

这是测试构建器类的样子:

public class TestBuilder<T, O>
{
    public TestBuilder(Class<T> eventClass)
    {
        this(eventClass, (Class<O>)eventClass);
    }

    private TestBuilder(Class<T> eventClass, Class<O> observableClass)
    {
        init();
    }

    public TestBuilder<T, O> withOnNext(Action1<O> actionNext)
    {
        mActionNext = actionNext;
        return this;
    }
}

2 个答案:

答案 0 :(得分:2)

我不认为Java可以在没有某种暗示的情况下推断出第二种通用​​类型。一种方法是在变量声明中给出类型:

 TestBuilder<String, String> testBuilder = new TestBuilder<>(String.class);
 testBuilder.withOnNext(new Action1<String>() {
     @Override
     public void call(String string) {
         //...
     }
 });

但您仍需要声明两个通用参数。

我要做的是在静态工厂方法中封装TO相同的信息:

public  class TestBuilder<T, O> {
    public static <T> TestBuilder<T, T>  create(Class<T> eventClass) {
        return new TestBuilder<T, T>(eventClass);
    }
    // ...
}

然后像这样调用它:

TestBuilder.create(String.class).withOnNext(...);

另一个选择是将信息封装在一个继承自TestBuilder

的单独类中
public class SimpleTestBuilder<T> extends TestBuilder<T,T> {
    public SimpleTestBuilder(Class<T> eventClass) {
        super(eventClass, eventClass);
    }
}

public class TestBuilder<T, O> {
    private TestBuilder(Class<T> eventClass, Class<O> observableClass) {
    }
    // ...
}

用作

    new SimpleTestBuilder<>(String.class).withOnNext(...);

另一个好的选择是在静态方法中封装信息OT相同:

public  class TestBuilder<T, O> {
    public static <T> TestBuilder<T, T>  create(Class<T> eventClass) {
        return new TestBuilder<T, T>(eventClass);
    }
    // ...
}

用作

TestBuilder.create(String.class).withOnNext(...);

答案 1 :(得分:0)

您可以为第一个构造函数引入一个帮助器类型变量,如下所示:

public class TestBuilder <T, O>
{
    public <H extends T, O> TestBuilder(Class<H> c)
    {
        this((Class) c, (Class) c);
    }

    public TestBuilder(Class<T> c1, Class<O> c2)
    {
        // ...
    }

    public static void main(String[] args)
    {
        TestBuilder<String, String> hw = new TestBuilder<>(String.class);
        System.out.println(hw);
    }
}

这将为构造函数创建一些unchecked警告,但不会在调用站点创建警告。请注意,虽然有些人可能会考虑这种广告实践,特别是因为不是每个人都知道构造函数类型参数。为了完整起见,构造函数的显式调用必须如下所示:

new<String> TestBuilder<>(String.class).doStuff()