Derive general class type parameters from one constructor parameter

I want the following:

In most cases, the general class will look like TestBuilder<X, X> , which means that T and O are of the same type. Therefore, I create two different constructors. I want to make anonymous new calls like new TestBuilder<>(...) (here I call <> anonymous).

Below are 4 examples of the constructor:

1) Constructor work call

 // 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) Call constructor with problems or does not work

 // 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) { } }); 

Question

Is there a way to get the 4th constructor to work? I don’t want to be forced to give two classes to constuctor, if I call it only one argument, the second generic class should β€œinherit” from the first in this case ... Instead of writing new TestBuilder<String, String>(String.class) , I want to write new TestBuilder<>(String.class) or at least new TestBuilder<String>(String.class) ...

Class

Here's what the test builder class looks like:

 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; } } 
+5
source share
2 answers

I don't think Java can infer a second generic type without any hint. One way is to specify the type of variable declaration:

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

But you still need to declare both common parameters.

What I would do is encapsulate the information that both the T and O methods are the same in the static factory method:

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

and then call it like this:

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

Another option is to encapsulate information in a separate class that inherits from 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) { } // ... } 

Used as

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

Another good option is to encapsulate O information in a static method:

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

Used as

 TestBuilder.create(String.class).withOnNext(...); 
+2
source

You can enter a variable of type helper for the first constructor, for example:

 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); } } 

This will create unchecked warnings for the constructor, but not on the call site. Please note, however, that some may consider this practice of advertising, especially since not everyone knows about constructor type parameters. For completeness, an explicit constructor call should look like this:

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

All Articles