1

I have a database table that contains a column named type. For every row in my database column I have to create an object depending on the type. At the moment I use if else statements for that:

if (type.equals("object1")){
    Object1 object1 = new Object1();
}
else if (type.equals("object2")){
    Object2 object2 = new Object2();
}

Somewhat nicer would be to use an enum, as the number of types is limited but is there a possibility to let the creation of an object depend on the value of the String?

I'm open to suggestions that might solve my problem in another way than I am trying to.

5 Answers 5

3

You can use

Object o = Class.forName(type).newInstance();

If you have an int and two Strings as arguments you need.

Object o = Class.forName(type)
                .getConstructor(int.class, String.class, String.class)
                .newInstance(intValue, string1, string2);

Another possibility is to use factory methods

Object o = getClass().getMethod("create_" + type).invoke(null);

static Object1 create_object1() {
     return new Object1(/* with args */);
}

static Object2 create_object2() {
     return new Object2(/* with other args */);
}

but the most flexible approach may be to use a switch

Object o;
switch(type) { // in Java 7
    case "object1": o = new Object1(); break;
    case "object2": o = new Object2(); break;

What would be more elegant is using closures in Java 8.

http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html

Sign up to request clarification or add additional context in comments.

7 Comments

I'm developing for Android so the switch statement will not work
Good point, same goes for closures. The first example will work. You may need to add a package at the start of the name and change the case of the first letter. ;)
I'm trying the Object o = Class.forName(type).newInstance(); I think it would suit me the best. I'm stuck however at passing the constructor variables. I need to pas an int and two Strings and this question addresses this but I can't seem to figure it out (or just understand what happens) stackoverflow.com/questions/234600/…
@J.Maes as you can read in the post you cite, you can use Constructor.newInstance() instead of Class.newInstance();. I've edited my answer, take a look.
@J.Maes Added an example for this case.
|
3

You could create a map from String to Class and use newInstance. That however relies on the existence of no-arg constructors.

import java.util.*;

class Test {
    public static void main(String[] args) throws Exception {
        Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
        classes.put("object1", Object1.class);
        classes.put("object2", Object2.class);

        String type = "object2";

        Object obj = classes.get(type).newInstance();

        //...
    }
}

class Object1 { ... }

class Object2 { ... }

5 Comments

Or all constructors having the same arguments. e.g. Object1(Object[] values)
I did think of using a Map, and I have done this in the past. If you have Java 7, a switch may be more elegant.
Yep :-) Putting the code you suggested in a function and returning the object would even save the programmer from a few (error prone) break statements :-)
Without closures, a function likely to be more verbose than use a break.
In my case, all classes will have the same constructor. I'll try the above method.
0
package main;

import java.util.ArrayList;
import java.util.List;

public class TempClass {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        List<Class> classes = new ArrayList<Class>() {{
            add(Class.forName("main.Object1"));
            add(Class.forName("main.Object2"));
        }};
        for (Class aClass : classes) {
            Object o = aClass.newInstance();
        }
    }
}


package main;

public class Object1 {
    public Object1() {
        System.out.println("Object1");
    }
}


package main;

public class Object2 {
    public Object2() {
        System.out.println("Object2");
    }
}

Comments

0

If the classes in question are part of an inheritance hierarchy and you happen to use some kind of mapping tool/framework like Hibernate or iBATIS/MyBatis, it might include a way to configure so called discriminators.

You could then configure your "type" column as the descriminator column and map the supported values to your classes. The framework will then instantiate the appropriate classes for you when you retrieve the objects from the database.

Comments

0

Using switch or if statements forces you to hard-code the various options, so you will obtain a not so flexible solution, in my opinion.

I always prefer to write code that is extensible for future software developments.

So I suggest you to use Object o = Class.forName(type).newInstance(); putting in your database the name of the class you want to instantiate and, if you need it, a custom label.

EDIT

If you have to pass some parameter to the constructors of the classes you have to instantiate, is convenient to use Constructor.newInstance() instead of Class.newInstance(); and use the Constructor object to instantiate the class, for example:

Class myClass = Class.forName(type);

// get the constructor you need specifying parameters type 
Constructor constructor = myClass.getConstructor(String.class);

Object myObject = constructor.newInstance("constructor-arg");

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.