2

I don't know if I have titled this correctly, but, I am looking for a way to instantiate a new object of a subclass based on user input. IE, I want to ask the user what sub class they want to create, and then create it based on that choice. So it may look like

 String category = CATEGORIES[Integer.parseInt(scanner.nextLine())];   
 items.add(new category(myString, myInt));

I am adding these into an ArrayList.

That new keyword seems to only accept an actual class though and not anything else. I have played around with built in Class methods but when i try to put those after the new call it fails. Pretty much anything I put after the new call except the class itself fails.

Is this something that is possible?

Thanks!

BrandenS
  • 591
  • 1
  • 5
  • 7
  • You're looking for Reflection. – SLaks Feb 09 '16 at 22:05
  • You could [instantiate the class using reflection](https://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html). Or you could use a switch statement. – khelwood Feb 09 '16 at 22:05
  • asking a user which class you have to instantiate is not really secure! – Jérémie B Feb 09 '16 at 22:07
  • 1
    Check out the factory design pattern. It should get you exactly what you're looking for. [link](http://howtodoinjava.com/design-patterns/implementing-factory-design-pattern-in-java/) – James Cootware Feb 09 '16 at 22:07
  • Just going to go with a switch. I knew I could use that I was just looking for a "cleaner" way but the reflection thing looks way more complicated. Thanks all! – BrandenS Feb 10 '16 at 01:01

3 Answers3

1

You are looking for reflection, and Class.forName() and Class.forName().newInstance()

Look: What is the difference between "Class.forName()" and "Class.forName().newInstance()"?

There is an example.

Look also: Initializing a class with Class.forName() and which have a constructor which takes arguments

Community
  • 1
  • 1
  • I see what this is driving at, but I'm not clear on how to make it actually work. Will this method still work if I have constructors on my subclasses? – BrandenS Feb 09 '16 at 22:59
1

I wouldn't recommend this, but it is possible with Reflection:

Object thing = Class.forName(category).getConstructor().newInstance();

This gets the class with the name stored in category, gets its no-argument constructor, and invokes it, storing the resulting Object in thing.

A lot can go wrong here; this will only work if none of the following are true:

  • There is no class with the given name.
  • The user says something like "String" instead of "java.lang.String". Class.forName(String s) only works with fully qualified names.
  • The class has no nullary constructor (a constructor that takes no arguments).

Also, as someone mentioned, this is a very insecure and unstable thing to do.

ostrichofevil
  • 749
  • 7
  • 19
  • 1
    Would there be a way to do this if i have a constructor that requires fields? – BrandenS Feb 09 '16 at 23:09
  • Yes. Look at the Javadocs here: https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getConstructor(java.lang.Class...) and here: https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Constructor.html#newInstance(java.lang.Object...) – ostrichofevil Feb 10 '16 at 12:21
0

Try this

public class Category {}
public class Foo extends Category { public Foo(String s, int i) {}}
public class Bar extends Category { public Bar(String s, int i) {}}
String[] CATEGORIES = { Foo.class.getName(), Bar.class.getName() };
static final Class<?>[] ARGTYPES = { String.class, int.class };

and

List<Category> items = new ArrayList<>();
String category = CATEGORIES[Integer.parseInt(scanner.nextLine())];   
items.add((Category)Class.forName(category)
    .getConstructor(ARGTYPES)
    .newInstance(myString, myInt));