Створення екземпляра за допомогою імені класу та конструктора виклику


312

Чи є спосіб створити екземпляр певного класу, задавши ім’я класу (динамічний) та передати параметри його конструктору.

Щось на зразок:

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

Де "MyAttributeValue"аргумент конструктору MyClass.

Відповіді:


497

Так, щось на кшталт:

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

Це, звичайно, буде працювати лише для одного рядкового параметра, але ви можете змінити його досить легко.

Зауважте, що ім'я класу повинно бути повністю кваліфікованим, тобто з простором імен. Для вкладених класів потрібно використовувати долар (як саме це використовує компілятор). Наприклад:

package foo;

public class Outer
{
    public static class Nested {}
}

Щоб отримати Classоб’єкт для цього, вам знадобиться Class.forName("foo.Outer$Nested").


5
newInstance()це метод varargs (так само GetConstructor()), немає необхідності у Objectстворенні явного масиву.
Йоахім Зауер

18
@Joachim: Я знаю, що це varargs, але оскільки у вас Object[]аргумент може бути складним , я вважаю за краще явно створювати масив у цьому випадку.
Джон Скіт

2
clazz.getConstructor (String.class); чому тут String.class?
Умаїр А.

2
@Neutralizer: Так, але я відповідав на питання, де це не потрібно бути динамічним.
Джон Скіт

3
@JonSkeet Я розумію, звідки ви беретесь, проте це не зовсім так просто - я дивився на документи, але був розгублений, але також якщо я перевірив його і він спрацював - нормально, тоді він працював - але якщо він не працював тоді Я був би не впевнений, якби проблема була через певну відсутність конфігурації чи щось з мого боку - часто, задаючи такі прості запитання, люди кидають корисні ласощі, які справді допомагають. Ось чому просте "так, що спрацювало б - якщо ви зробите це так" або "немає ніякого способу", справді допомагає. Але зараз я розумію, що немає способу
ycomp

97

Ви можете використовувати Class.forName()для отримання Classоб'єкта потрібного класу.

Потім використовуйте getConstructor()для пошуку потрібного Constructorоб'єкта.

Нарешті, зателефонуйте newInstance()на цей об’єкт, щоб отримати новий примірник.

Class<?> c = Class.forName("mypackage.MyClass");
Constructor<?> cons = c.getConstructor(String.class);
Object object = cons.newInstance("MyAttributeValue");

81

Можна використовувати роздуми

return Class.forName(className).getConstructor(String.class).newInstance(arg);

3
Якщо використовується конструктор за замовчуванням, видаліть значення параметра String.class, наприклад, поверніть Class.forName (className) .getConstructor (). NewInstance (arg);
Віджай Кумар

21
@VijayKumar Я думаю, ти маєш на увазі Class.forName(className).getConstructor().newInstance();;)
Пітер Лоурі

14

Якщо у класу є лише один порожній конструктор (наприклад, Activity або Fragment etc., android class):

Class<?> myClass = Class.forName("com.example.MyClass");    
Constructor<?> constructor = myClass.getConstructors()[0];

2
Це мені допомогло. Constructor<?> ctor = clazz.getConstructor(String.class)здавалося, не працює на мене.
Лео С Хань

8

при використанні (тобто) getConstructor(String.lang)конструктор повинен бути оголошений загальнодоступним. Інакше а NoSuchMethodExceptionкидається.

якщо ви хочете отримати доступ до непублічного конструктора, ви повинні використовувати його (тобто) getDeclaredConstructor(String.lang).



4

Дуже простий спосіб створити об’єкт у Java за Class<?>допомогою передачі аргументів конструктора:

Випадок 1: - Ось невеликий код цього Mainкласу:

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);
    }

}

І ось Baseструктура класу:

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+")");
    }

}

Випадок 2: - Ви можете кодувати аналогічно для конструктора з кількома аргументами та конструктора копіювання. Наприклад, для передачі 3 аргументу як параметру Baseконструктору потрібно буде створити конструктор в класі і змінити код вище, як:

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

І ось базовий клас повинен якось виглядати так:

public class Base {

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

Примітка: - Не забувайте обробляти різні винятки, які потрібно обробляти в коді.


Інший спосіб - також клонувати () існуючий об'єкт java. Це створює копію існуючого об’єкта Java. У цьому випадку вам також доведеться обробити концепцію «Глибока копія» або «Неглибока копія».
Рахул Райна

2

Якщо хтось шукає спосіб створити екземпляр класу, незважаючи на клас, що відповідає шаблону Singleton, ось такий спосіб зробити це.

// 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();

Це працює лише для класів, які реалізують однотонний шаблон за допомогою приватного конструктора.


1

Ви також можете викликати методи всередині створеного об'єкта.

Ви можете створити об'єкт миттєво, викликавши перший констрактор, а потім викликаючи перший метод у створеному об'єкті.

    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);

Як ви дізнаєтесь, що найперший конструктор приймає Stringза параметр? Стає трохи безладним, коли ви змінюєте порядок конструктора
Farid

@Farid з документації про клас
Hatem Badawi

Ще getConstructor(ClassName.class)краще, гадаю. Навіть якщо порядок конструкторів змінюється в класі, не потрібно знаходити позицію вручну
Фарид

@Farid - c.getDeclaredMethods () [0] .invoke (об'єкт, об'єкт ... MethodArgs); в деяких випадках вам може знадобитися спеціальний конструктор, але ви маєте рацію.
Хатем Бадаві

1

Ще одна корисна відповідь. Як я можу використовувати getConstructor (params) .newInstance (args)?

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

У моєму випадку конструктор мого класу приймає Webdriver як параметр, який використовується нижче коду:

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.