3

How do I implement the following pseudocode in Java?

Object getInstance(Class<?> type)
{
  switch (type)
  {
    case A.class:
      return createA(param1, param2);
    case B.class:
      return createB(param3, param4, param5);
    default:
      throw new AssertionError("Unknown type: " + type);
  }
}

I know I can probably implement this using a Map<Class<?>, Callable<Object>> (mapping classes to a method that returns an object) but is there a more efficient/readable way to do this?

UPDATE: I'm sorry for the misleading pseudo code. I did not mean to imply that the classes have no-arg constructors. Each class is constructed differently. I know if-else works but it is not great from an efficiency point of view. It is O(n).

7
  • switch in Java is very limited. You can switch on Strings and numbers, that's it. I'm not sure I'd argue for using the (string) type name as the switch .. which leaves the alternative(s) of switching away from switch. Commented Jan 15, 2014 at 5:40
  • 1
    @user2864740 - switch on Enums as well. Can't do it on Objects in general though. Commented Jan 15, 2014 at 5:42
  • @Chris True, I still group them together with numbers in my head. I blame C# :> Commented Jan 15, 2014 at 5:43
  • Have a look here too stackoverflow.com/questions/5579309/switch-instanceof Commented Jan 15, 2014 at 5:48
  • 2
    @BrianRoach, it works but it's a maintenance nightmare. If a class is renamed, the code will break silently. Refactoring tools handle renaming classes, but not Strings referencing classes. Ideally, the code should follow class renames automatically. Commented Jan 31, 2014 at 15:03

4 Answers 4

2

How about using the Class object to create a new instance?

private static final Set<Class> ALLOWED_CLASSES = 
    new HashSet<>(Arrays.asList(A.class, B.class));

Object getInstance(Class<?> type) {
    if (!ALLOWED_CLASSES.contains(type)) {
        throw new AssertionError("Unknown type: " + type);
    }
    return type.newInstance();
}
Sign up to request clarification or add additional context in comments.

3 Comments

+1 - with the caveat that this only works if the class has the nullary constructor
I think this would fail, if it is inner class
Duplicate of stackoverflow.com/a/21130129/14731 (and won't work for the same reason).
0

Instead of using switch, just use if.

if (type == A.class) {
    return new A();
} else if (type == B.class) {
    return new B();
} else {
    throw new AssertionError("Unknown type: " + type);
}

This way you can also handle more detailed cases in your if conditions, like subclasses, or interfaces, etc. It also allows your constructors to optionally contain other arguments (following a factory-like pattern), which becomes harder if you just throw them into a map or use reflection.

Comments

0

If all constructors invoked without parameters,

Object getInstance(Class<?> type)  {
  return type.newInstance();
}

Otherwise, if the number of variants is small, use if statements, otherwise use map as intended.

Comments

0

If none of the calls to new require parameters, then you can use newInstance(). Then we just add some error condition code:

private static final List<Class> classes = Arrays.asList(A.class, B.class, ...);

public static Object getInstance(Class<?> type) {
    if (classes.contains(type))
        return type.newInstance();
    throw new AssertionError("Unknown type: " + type);
}

1 Comment

Sorry for the misleading pseudocode. I didn't mean to imply that classes have no-arg constructors. Each type has its own construction mechanism (different parameters for different classes). Thanks anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.