Java generators and specialized constructors

(This is probably a duplicate, but I could not find it), feel free to specify it)

Consider the following Java class:

public class A<T0, T1> { public A(T0 t0, T1 t1) { ... } } 

Creating this class is easy using something along the lines of new A<Integer, String>(1, "X") .

Suppose now that most instances of this class have String as the second parameter of type T1 and that the object of this type used in the constructor call is also pretty standard.

If A did not use generics, the general extension would be an additional constructor without a second argument:

 public class A { public A(int t0, String t1) { ... } public A(int t0) { this(t0, new String("X")); } } 

Unfortunately, this does not seem possible for a class that uses generics - at least without coercion:

  public A(T0 t0) { this(t0, (T1)(...)); } 

Cause? Although this constructor accepts only one argument, it still uses two type parameters, and there is no way to know a priori that any type of T1 class resource user will be compatible with the default value used in the constructor.

A slightly more elegant solution involves using a subclass:

  public class B<T0> extends A<T0, String> { ... } 

But this approach forces another branch in the class hierarchy and another class file with what is mainly a code template .

  • Is there a way to declare a constructor that forces one or more type parameters for a particular type? Something with the same effect as using a subclass, but without the hassle?

  • Is there anything fundamentally wrong with my understanding of generics and / or my design? Or is this a real problem?

+7
source share
6 answers

The easiest way is to simply add a static creation method.

 public static <T0> A<T0,String> newThing(T0 t0) { return new A<T0,String>(t0, "X"); } 

(Possibly choose a name suitable for the particular use. Usually there is no need for new String("...") .)

From Java SE 7 you can use diamond:

 A<Thing,String> a = new A<>(thing); 
+6
source

As I understand it, you want to have a second constructor that (if called) will cause the general type T1 to be String.

However, generators are specified before you call the constructor.

This second constructor, if valid, may allow someone to do this:

 B<Integer, Integer> b = new B<Integer, Integer>(5); 

The error here is that you specified the second type of the generic type as an integer before invoking the constructor. And then the constructor theoretically defines the second generic type as String. That is why I believe that this is not permitted.

+2
source

"Most instances" is a root problem.

Either T1 is parameterized or not. A constructor with one argument assumes both. This is the problem.

Subclassing solves the problem if all instances satisfy T1 = String.

The named constructor / factory method also solves the problem by guaranteeing T1 = String.

  public static <T0> A<T0,String> makeA( T0 t0 ) { return new A<T0,String>( t0, "foo" ); } 
+1
source

You can qualify generic types, i.e.

 A<T0, T1 super MyDefaultType> { public A(T0 t0) { this(t0, new MyDefaultType()); } } 

You cannot use T1 extends MyDefaultType , because if you define a subclass, the instance of MyDefaultType will not be compatible with the T1 type.

+1
source

Is there a way to declare a constructor that forces one or more type parameters for a particular type? Something with the same effect as using a subclass, but without the hassle?

I believe this is not possible. Think about it. The developer defines a class that can be generic, i.e. The type of parameter is determined when creating the object. How can a developer define a constructor that forces the user to use a particular type of parameter?

EDIT: If you need it, you need to create a factory or factory method that creates instances of this class with a predefined parameter type.

0
source

Subclass As far as I have been taught, this is one of the great features of OOP. Enjoy it. Disk space is cheap.

If this is a problem with future code maintenance, consider creating an original abstract class and creating two subclasses (one with a constructor with a double generator and one with a single.

0
source

All Articles