Чи є спосіб інстанціювати клас на ім'я на Java?


102

Я розглядав як питання: Instantiate клас із його рядкового імені, яке описує, як створити інстанціювання класу при його імені. Чи є спосіб це зробити на Java? У мене буде ім'я пакета та ім'я класу, і мені потрібно мати можливість створити об'єкт, що має саме це ім'я.


Ми інстанціруем в клас , і результат є об'єктом (або: екземпляр ).
Андреас Долк

1
Відповідь "так", але я думаю, ви повинні запитати, чи це гарна ідея. З великою силою (роздумом) виходить велика відповідальність, і вам слід користуватися нею, лише якщо ви розумієте і враховували наслідки.
c1moore

Відповіді:


238

Два способи:

Спосіб 1 - лише для класів, що мають конструктор без аргументів

Якщо у вашому класі є конструктор без аргументів, ви можете отримати Classоб’єкт, Class.forName()використовуючи newInstance()метод для створення екземпляра (однак, будьте обережні, що цей метод часто вважається злим, оскільки він може перемогти перевірені винятки Java).

Наприклад:

Class<?> clazz = Class.forName("java.util.Date");
Object date = clazz.newInstance();

Спосіб 2

Альтернативний більш безпечний підхід, який також працює, якщо у класу немає конструкторів без аргументів - це запитувати об’єкт класу, щоб отримати його Constructorоб'єкт і викликати newInstance()метод на цьому об’єкті:

Class<?> clazz = Class.forName("com.foo.MyClass");
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
Object instance = constructor.newInstance("stringparam", 42);

Обидва методи відомі як рефлексія . Зазвичай вам доведеться вловлювати різні винятки, які можуть статися, включаючи такі речі:

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

привіт, щойно ми створили об’єкт newInstance(), чи могли б ми повернути його до власного об’єкта?
GMsoF

@Simon Ви можете розробити / дати покажчик про менеджера з безпеки?
Рам

Я цього не розумію. Я хочу отримати доступ до класу в невідомому файлі в якомусь іншому каталозі, у мене є лише ім'я шляху / файлу у вигляді рядка. Рядок "dir / unkonwn.java". Виклик Class.forName ("dir / unknown") дає мені помилки.
Джон Ктейджик

Як ми можемо кинути instanceв com.foo.MyClass? враховуючи, що com.foo.MyClass - це лише рядок
Sanket9394

14
MyClass myInstance = (MyClass) Class.forName("MyClass").newInstance();

15
Варто зазначити, що це не працює, якщо у класу немає конструктора без параметрів (і є інші конструктори) або якщо безпараметричний конструктор недоступний.
Давуд ібн Карім

3

використовуйте Class.forName ("Назва рядка класу"). newInstance ();

Class.forName("A").newInstance();

Це призведе до ініціалізації класу A.


Не працює для мене, навіть якщо заздалегідь вказано ім'я пакета. :(
trusktr

3

Щоб полегшити отримання повноцінного імені класу з метою створення екземпляра Class.forName(...), можна скористатися Class.getName()методом. Щось на зразок:

class ObjectMaker {
    // Constructor, fields, initialization, etc...
    public Object makeObject(Class<?> clazz) {
        Object o = null;

        try {
            o = Class.forName(clazz.getName()).newInstance();
        } catch (ClassNotFoundException e) {
            // There may be other exceptions to throw here, 
            // but I'm writing this from memory.
            e.printStackTrace();
        }

        return o;
    }
}

Тоді ви можете відкинути об'єкт, до якого ви повертаєтесь, у будь-який клас, до якого ви переходите makeObject(...):

Data d = (Data) objectMaker.makeObject(Data.class);

1
Ви не можете просто clazz.newInstance()замість getNameтогочасного fromName?
user276648

1

Використовуйте відбиття Java

Створення нових об'єктів Не існує еквіваленту виклику методу для конструкторів, тому що виклик конструктора еквівалентно створенню нового об'єкта (якщо бути найбільш точним, створення нового об'єкта передбачає як розподіл пам'яті, так і побудову об'єкта). Тож найближчим еквівалентом попереднього прикладу є:

import java.lang.reflect.*;

   public class constructor2 {
      public constructor2()
      {
      }

      public constructor2(int a, int b)
      {
         System.out.println(
           "a = " + a + " b = " + b);
      }

      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("constructor2");
           Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct 
              = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

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




0

щось подібне повинно працювати ...

String name = "Test2";//Name of the class
        Class myClass = Class.forName(name);
        Object o = myClass.newInstance();

0

Використання newInstance()прямо не використовується, як у Java 8. Потрібно використовувати Class.getDeclaredConstructor(...).newInstance(...)відповідні винятки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.