1

I need to instantiate an object of one of two different types, depending on a conditional. Both types take the same arguments to their constructors, and both are subclasses of a master type. Can I define a reference to the correct type inside the conditional and then instantiate the object using that reference? Quick example:

if (v == "bob") {
   Object myType = bobType;
} else {
   Object myType = otherType;
}
SuperType instance = new myType(arg1, arg2);

This doesn't work; is there a correct syntax for this in java? This is as a shortcut to doing this:

if (v == "bob") {
   SuperType instance = new bobType(arg1, arg2);
} else {
   SuperType instance = new otherType(arg1, arg2);
}

I'm actually making several instances, all of the same type, that all take a long list of arguments, and I wanted to avoid exactly repeating myself except for the type.

Igor Serebryany
  • 3,307
  • 3
  • 29
  • 41
  • everyone's answers are amazing; i wish i could accept more than one. i'm going to accept jacobm's because he explains the correct way to do something like this (although, yeah, it's a little verbose). – Igor Serebryany Oct 10 '12 at 00:28

4 Answers4

3

You can, but you have to use the Reflection API. Is there some reason you couldn't write it like this:

SuperType instance;
if (v == "bob") {
   instance = new bobType(arg1, arg2);
} else {
   instance = new otherType(arg1, arg2);
}

Otherwise what you want is to use the Class type to get a reference to the constructor, then you can call the constructor directly:

  SuperType instance;
  Class<? extends SuperType> clazz;
  Constructor<? extends SuperType> constructor;
  if ("bob".equals(v)) {

       clazz = bobType.class;
    } else {
       clazz = otherType.class;
    }
  //subbing in types of arg1 and arg2 of course
  constructor = class.getConstructor(String.class, String.class);
  instance = constructor.newInstance(arg1, arg2);

So if your goal is simply brevity, it's not really much less verbose, plus reflection throws various checked exceptions you will need to handle. If you know all the possible types at compile time, there isn't really much advantage. It becomes useful if you don't know all the types and are looking up classes from other libraries by name.

Affe
  • 47,174
  • 11
  • 83
  • 83
2

It is possible to use reflection for this, but in most cases it'd be more idiomatic to define factories. For instance,

interface MyFactory {
  SuperType newInstance(Foo arg1, Bar arg2);
}

class BobFactory implements MyFactory {
  public BobType newInstance(Foo arg1, Bar arg2) {
    return new BobType(arg1, arg2);
  }
}

class OtherFactory implements MyFactory {
  public OtherType newInstance(Foo arg1, Bar arg2) {
    return new OtherType(arg1, arg2);
  }
}

void myMethod() {
  MyFactory factory;
  if (v == "bob") {
    factory = new BobFactory();
  } else {
    factory = new OtherFactory();
  }
  SuperType instance = factory.newInstance(arg1, arg2);
}

This is more verbose than you're imagining, but has the advantage that if you ever change the constructors for BobType or OtherType, the compiler will catch that you need to update this code, rather than it crashing at runtime.

jacobm
  • 13,790
  • 1
  • 25
  • 27
1

It's a bit more complicated in java, you need to create an instance by using the classname. Have a look at this question: Creating an instance using the class name and calling constructor

Community
  • 1
  • 1
Stefan Neubert
  • 1,053
  • 8
  • 22
0

Your code:

if (v == "bob") {
   Object myType = bobType;
} else {
   Object myType = otherType;
}
SuperType instance = new myType(arg1, arg2);

To my understanding what you want is to instantiate different types according to a condition.

You can choose between declaring a variable so that it's scope exceeds the if-else condition (preferable, we'll call it option #1) and creating a factory constructor so that you instantiate the right type (less likely to be needed, seems like an overkill, option #2).

Option #1:

Simply break the declaration:

// declare "instance" so it exists inside if-else AND after condition
SuperType instance; 
if (v == "bob") {
   // instantiate "instance"
   instance = new bobType(arg1, arg2);
} else {
   // instantiate "instance"
   instance = new otherType(arg1, arg2);
}
// "instance" is now instantiated

Option #2:

Background: http://en.wikipedia.org/wiki/Factory_method_pattern

Basically what you do is create an interface to construct SuperType types. Obviously both classes (bobType and otherType) should implement it - so that you can instantiate the object immediately. This doesn't rid you of making a "factory" accessible within the code, and if it's not a recurring operation, option #1 is preferable.

Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88