375

Is there a way to create an instance of a particular class given the class name (dynamic) and pass parameters to its constructor.

Something like:

Object object = createInstance("mypackage.MyClass","MyAttributeValue");

Where "MyAttributeValue" is an argument to the constructor of MyClass.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
TheLameProgrammer
  • 4,037
  • 5
  • 19
  • 16

10 Answers10

569

Yes, something like:

Class<?> clazz = Class.forName(className);
Constructor<?> ctor = clazz.getConstructor(String.class);
Object object = ctor.newInstance(new Object[] { ctorArgument });

That will only work for a single string parameter of course, but you can modify it pretty easily.

Note that the class name has to be a fully-qualified one, i.e. including the namespace. For nested classes, you need to use a dollar (as that's what the compiler uses). For example:

package foo;

public class Outer
{
    public static class Nested {}
}

To obtain the Class object for that, you'd need Class.forName("foo.Outer$Nested").

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 6
    `newInstance()` is a varargs method (just as `GetConstructor()`), there's no need for explicit `Object`-array creation. – Joachim Sauer May 23 '11 at 08:28
  • 20
    @Joachim: I know it's varargs, but as it can get tricky when you have an `Object[]` argument, I prefer to create the array explicitly in this case. – Jon Skeet May 23 '11 at 08:32
  • 2
    clazz.getConstructor(String.class); why String.class here? – Umair A. Jul 19 '14 at 19:38
  • @Neutralizer: Because the OP has a string argument to pass. – Jon Skeet Jul 19 '14 at 19:49
  • can't it be dynamic? I mean I don't want to hint about the type of arguments beforehand. Is it possible? – Umair A. Jul 19 '14 at 19:50
  • 2
    @Neutralizer: Yes, but I was answering a question where it didn't need to be dynamic. – Jon Skeet Jul 19 '14 at 21:41
  • yeah I know. I wanted to know if can it be dynamic. thanks anyway – Umair A. Jul 19 '14 at 22:23
  • Will using the "Simplename" (no packages, just the class name) work? or must the class name be fully qualified? – ycomp Oct 11 '15 at 16:51
  • @ycomp: What did the documentation of `Class.forName` and your tests show you? :) – Jon Skeet Oct 11 '15 at 17:35
  • well docs were inconclusive (it says fully qualified but gives the example of Class "Foo"), which is why I asked - and to write tests for such a simple thing doesn't make much sense when there are probably many people that know the answer to such a simple question. – ycomp Oct 11 '15 at 17:46
  • @ycomp: I have to say, that *sounds* like "I couldn't be bothered to check" - you could very easily have checked for yourself, and then suggested "You might like to mention that the class name has to be a fully-qualified one." – Jon Skeet Oct 11 '15 at 17:50
  • 3
    @JonSkeet I understand where you are coming from, however it's not quite that simple - I did look at the docs but was confused, but also if I tested it and it worked - ok then it worked - but if it didn't work then I would have been unsure if the problem was due to some lack of configuration or something on my part - often when asking such simple questions, people throw in useful tidbits that really help. That's why a simple "yes that would work - if you do it this way" or "no there's no way", really helps. But my understanding now is that there's no way – ycomp Oct 11 '15 at 19:32
  • Why is `String.class` a necessary argument to `getConstructor`? Many many examples online do this. A few of the examples show the intent being to get the constructor for a class _actually_ has a `String` parameter for its constructor, while others do not. – sherrellbc May 18 '18 at 15:28
  • @sherrellbc It's just a simple way of showing an example of passing an argument. Note that the question *asks* about a class with a string parameter in the constructure, so it's not like this has come out of nowhere... – Jon Skeet May 18 '18 at 18:55
  • what is `ctorArgument`? – Alexander Mills Feb 14 '19 at 07:20
  • @AlexanderMills: The argument you want to pass to the constructor. – Jon Skeet Feb 14 '19 at 08:44
116

You can use Class.forName() to get a Class object of the desired class.

Then use getConstructor() to find the desired Constructor object.

Finally, call newInstance() on that object to get your new instance.

Class<?> c = Class.forName("mypackage.MyClass");
Constructor<?> cons = c.getConstructor(String.class);
Object object = cons.newInstance("MyAttributeValue");
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
93

You can use reflections

return Class.forName(className).getConstructor(String.class).newInstance(arg);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 4
    If using default constructor, remove the String.class parameter value e.g. return Class.forName(className).getConstructor().newInstance(arg); – Vijay Kumar Aug 05 '13 at 19:40
  • 28
    @VijayKumar I think you mean `Class.forName(className).getConstructor().newInstance();` ;) – Peter Lawrey Aug 06 '13 at 08:05
17

If class has only one empty constructor (like Activity or Fragment etc, android classes):

Class<?> myClass = Class.forName("com.example.MyClass");    
Constructor<?> constructor = myClass.getConstructors()[0];
tier777
  • 1,005
  • 12
  • 11
  • 2
    This is what helped me. `Constructor> ctor = clazz.getConstructor(String.class)` didn't seem to work for me. – BrockLee Dec 14 '14 at 02:56
9

when using (i.e.) getConstructor(String.lang) the constructor has to be declared public. Otherwise a NoSuchMethodException is thrown.

if you want to access a non-public constructor you have to use instead (i.e.) getDeclaredConstructor(String.lang).

5

Another helpful answer. How do I use getConstructor(params).newInstance(args)?

return Class.forName(**complete classname**)
    .getConstructor(**here pass parameters passed in constructor**)
    .newInstance(**here pass arguments**);

In my case, my class's constructor takes Webdriver as parameter, so used below code:

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
Community
  • 1
  • 1
user3181500
  • 401
  • 1
  • 5
  • 12
5

If anyone is looking for a way to create an instance of a class despite the class following the Singleton Pattern, here is a way to do it.

// Get Class instance
Class<?> clazz = Class.forName("myPackage.MyClass");

// Get the private constructor.
Constructor<?> cons = clazz.getDeclaredConstructor();

// Since it is private, make it accessible.
cons.setAccessible(true);

// Create new object. 
Object obj = cons.newInstance();

This only works for classes that implement singleton pattern using a private constructor.

Omer
  • 151
  • 2
  • 11
4

Very Simple way to create an object in Java using Class<?> with constructor argument(s) passing:

Case 1:- Here, is a small code in this Main class:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Main {

    public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        // Get class name as string.
        String myClassName = Base.class.getName();
        // Create class of type Base.
        Class<?> myClass = Class.forName(myClassName);
        // Create constructor call with argument types.
        Constructor<?> ctr = myClass.getConstructor(String.class);
        // Finally create object of type Base and pass data to constructor.
        String arg1 = "My User Data";
        Object object = ctr.newInstance(new Object[] { arg1 });
        // Type-cast and access the data from class Base.
        Base base = (Base)object;
        System.out.println(base.data);
    }

}

And, here is the Base class structure:

public class Base {

    public String data = null;

    public Base() 
    {
        data = "default";
        System.out.println("Base()");
    }

    public Base(String arg1) {
        data = arg1;
        System.out.println("Base("+arg1+")");
    }

}

Case 2:- You, can code similarly for constructor with multiple argument and copy constructor. For example, passing 3 arguments as parameter to the Base constructor will need the constructor to be created in class and a code change in above as:

Constructor<?> ctr = myClass.getConstructor(String.class, String.class, String.class);
Object object = ctr.newInstance(new Object[] { "Arg1", "Arg2", "Arg3" }); 

And here the Base class should somehow look like:

public class Base {

    public Base(String a, String b, String c){
        // This constructor need to be created in this case.
    }   
}

Note:- Don't forget to handle the various exceptions which need to be handled in the code.

Rahul Raina
  • 3,322
  • 25
  • 30
  • Another way is also by clone() the existing java object. This creates a copy of an existing Java object. For this case, you also have to handle the Deep copy or Shallow copy concept. – Rahul Raina Jun 01 '19 at 21:26
4

You want to be using java.lang.reflect.Constructor.newInstance(Object...)

Alan Escreet
  • 3,499
  • 2
  • 22
  • 19
1

You can also invoke methods inside the created object.

You can create object instant by invoking the first constractor and then invoke the first method in the created object.

    Class<?> c = Class.forName("mypackage.MyClass");
    Constructor<?> ctor = c.getConstructors()[0];
    Object object=ctor.newInstance(new Object[]{"ContstractorArgs"});
    c.getDeclaredMethods()[0].invoke(object,Object... MethodArgs);
Hatem Badawi
  • 536
  • 4
  • 9
  • How will you know that the very first constructor takes `String` as a parameter? Becomes a little messy when you change constructor order – Farid Oct 01 '19 at 11:17
  • @Farid from class documentation – Hatem Badawi Oct 03 '19 at 04:15
  • Still `getConstructor(ClassName.class)` is better, I guess. Even if the order of constructors changes in class, no need to find the position manually – Farid Oct 03 '19 at 04:24
  • @Farid - c.getDeclaredMethods()[0].invoke(object,Object... MethodArgs); specifies special constructor in some cases you may need this ;but you are right. – Hatem Badawi Oct 04 '19 at 13:32