2

I have a class let's call it Creator which contains two instance fields. Those fields belong to a parent class A. In the Creator's constructor I want to pass a child of class A and then to create two objects from that passed type and assign the references to the two fields. How can I do something like that? I don't know how to make this generalization.

EDIT: the class Creator shall only accept types that are children of A or A itself. So not any other general type. AND A does not have a no-argument constructor

So like this, here GeneralClassifier is A and doesn't have a no-argument constructor:

public class TwoLevelClassifier <T> {

    private GeneralClassifier firstCl, secondCl;

    //The passed type shall *only* be a GeneralClassifier or a child of it
    public TwoLevelClassifier( GeneralClassifier cl ) {
        firstCl = //create a new classifier that is of the type passed to the constructor
        secondCl = //create a new classifier that is of the type passed to the constructor
    }

}

I'm not sure, but maybe this feature is called generics in java?

Jack Twain
  • 6,273
  • 15
  • 67
  • 107
  • 1
    You should use reflection. See this: http://stackoverflow.com/questions/10470263/create-new-object-using-reflection – Massimo Jan 17 '14 at 15:06
  • 1
    Why not use generics? `public class Creator {` – crush Jan 17 '14 at 15:08
  • Is it a requirement to pass an instance of the children type as a parameter of the ctor? You aren't doing anything with it, so I assume not – crush Jan 17 '14 at 15:10
  • There is _a lot_ of information out there on generics in Java. Do some looking. http://docs.oracle.com/javase/tutorial/java/generics/ – GriffeyDog Jan 17 '14 at 15:11

2 Answers2

7

You can do this using reflection:

public class Creator<A> {
    A a, b;

    public Creator(Class<A> childrenType) throws IllegalAccessException, InstantiationException {
        a = childrenType.newInstance();
        b = childrenType.newInstance();
    }
}

Note: This assumes that the class that you use has a no-arguments constructor.

edit You substantially edited your original question.

For the requirement that the type A should only be a GeneralClassifier or a subclass of that, add a constraint to the type parameter:

public class Creator<A extends GeneralClassifier> {

For the requirement that the class A does not have a no-argument constructor: Then you have to lookup the constructor that you want to use and call it with the appropriate arguments. You will have to know in advance what constructor you have to call. Suppose that you want to call a constructor that takes a String. Then it would be something like this:

Constructor<A> constr = childrenType.getConstructor(String.class);
a = constr.newInstance("Hello");
b = constr.newInstance("Bye");

See the API docs of class java.lang.Class and the package java.lang.reflect.

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • 1
    The answer is ok, but I should point out that using reflection should always be a last resort. – Mario Stoilov Jan 17 '14 at 15:08
  • are generics and reflection the same thing? – Jack Twain Jan 17 '14 at 15:08
  • No, [generics](http://docs.oracle.com/javase/tutorial/java/generics/) and [reflection](http://docs.oracle.com/javase/tutorial/reflect/) (<= click those links) are two completely different things. – Jesper Jan 17 '14 at 15:11
  • Why not `a = new A();`? – crush Jan 17 '14 at 15:11
  • 1
    @crush because that does not work, `A` is a type parameter, not a concrete type. – Jesper Jan 17 '14 at 15:11
  • @AlexTwain Nope, they are different things. Reflection allows you to dynamically instantiate and manipulate classes you have not imported (say, imagine having different and pluggable implementations for your IMovie interface: AVIMovie, MPEGMovie, MP4Movie...). Generics allows you to build, for example, collections of anonymous objects. However, you have to instance the collection for a concrete type, which brings to compile time any error that would pass unnoticed with collections of Objects (which is how it was before generics) – Jorge_B Jan 17 '14 at 15:13
  • @MarioStoilov I beg to differ, reflection is your only resort if you want to decouple abstract interfaces from concrete implementations in a situation like the IMovie/concrete movies example I used before – Jorge_B Jan 17 '14 at 15:15
  • the class Creator shall only accept types that are children of A or A itself. – Jack Twain Jan 17 '14 at 17:30
  • So not any other general type – Jack Twain Jan 17 '14 at 17:31
3

You can do something similar with reflection and generics, like so

// <TYPE> is the generic type.
public class Creator<TYPE> {
    TYPE a = null, b = null;

    public Creator(Class<TYPE> childrenType) {
        try {
            // newInstance is reflection.
            a = childrenType.newInstance();
            b = childrenType.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

or, you can avoid the reflection by passing in the instances of TYPE, with this constructor (for example) -

public Creator(TYPE a, TYPE b) {
    this.a = a;
    this.b = b;
}
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249