If generic enums were possible in Java, then this would be a simple solution, but unfortunately that is not possible. Here is an option that may suit your needs.
Create a generic interface that contains your newA
method:
public interface AType<T extends A> { T newA(final int a);}
Then create a class that will contain public static
instances of this interface, somewhat simulating an enum:
public static class ATypes { public static AType<A1> A1_TYPE = new AType<A1>() { @Override public A1 newA(int a) { return new A1(a); } }; public static AType<A2> A2_TYPE = new AType<A2>() { @Override public A2 newA(int a) { return new A2(a); } };}
Thanks to Java 8+ function references, we can simplify this class significantly:
public static class ATypes { public static AType<A1> A1_TYPE = A1::new; public static AType<A2> A2_TYPE = A2::new;}
Then, change the syntax of your insertA
method to be generic with the bounds of T extends A
:
public static <T extends A> void insertA(final AType<T> t, final List<T> al, final int x) { final T newA = t.newA(x); al.add(newA);}
Now the following code will work:
public static void main(String[] args) { final List<A1> list1 = new ArrayList<>(); final List<A2> list2 = new ArrayList<>(); insertA(ATypes.A1_TYPE, list1, 1); insertA(ATypes.A2_TYPE, list2, 2); // the following will not compile (types switched) // insertA(ATypes.A2_TYPE, list1, 1); // insertA(ATypes.A1_TYPE, list2, 2);}
Alternatively, you could always skip the intermediate type and just pass the function reference directly like so:
public static void main(String[] args) { final List<A1> list1 = new ArrayList<>(); final List<A2> list2 = new ArrayList<>(); insertA(A1::new, list1, 1); insertA(A2::new, list2, 2);}public static <T extends A> void insertA(final Function<Integer, T> t, final List<T> al, final int x) { final T newA = t.apply(x); al.add(newA);}