Динамическая загрузка класса в Java

#java #dynamic

#java #динамический

Вопрос:

Я просмотрел синтаксис и поискал в api, но все еще не понимаю процесса. Я также искал Stackoverflow. Как правильно загружать класс и динамически создавать из него объект? Другими словами, я хочу, чтобы пользователь указал, какой тип объекта он хочет создать, а затем создал объект этого типа. Мне не нужно меню, потому что я хочу, чтобы они могли выбирать любой класс в текущем каталоге.

Комментарии:

1. Вы пытаетесь загрузить класс из binary.class по файлу или по имени класса?

2. @JustinWaugh Привет, Джастин, подходит ли принятый ответ для загрузки файла .class?

Ответ №1:

Предполагая, что класс не имеет конструктора-arg, самым простым способом было бы —

 Object newObject = Class.forName(strFullyQualifiedClassName).newInstance();
  

Ссылка — java.lang.Класс

Комментарии:

1. что, если в нем есть arg, и как мне вызвать метод в классе — как мне привести newObject только по имени класса? Когда я пытаюсь вызвать метод класса для типа Object, он сообщает мне, что метод не определен для object.

2. Если вы не знаете тип класса во время компиляции, вам придется использовать отражение для поиска и вызова методов. Если у конструктора есть аргумент, который вы используете getDeclaredConstructor() для класса, возвращаемого из Class.forName , как показано в ответе Майка Сэмюэля

3. 1 Джастину. Также, практически говоря, не может быть, чтобы вы абсолютно ничего не знали об этом классе, поскольку тогда его будет очень сложно использовать на самом деле. Наличие этих неизвестных классов, реализующих определенный интерфейс, обычно является хорошей стратегией. затем вы можете ссылаться на эти объекты с помощью интерфейсов, чтобы вызывать для них методы и т.д.

4. каково полное имя класса для класса?

5. Вам не следует использовать .newInstance() . Если конструктор с нулевым аргументом выдает проверенные исключения, .newInstance() они будут отображаться как исключения во время выполнения, поэтому вы потеряете безопасность исключений. Из javadoc : «Использование этого метода эффективно обходит проверку исключений во время компиляции, которая в противном случае была бы выполнена компилятором».

Ответ №2:

ClassLoader.loadClass загрузит класс. Вы получаете classloader с помощью myClass.getClassLoader() и вам следует вернуться к ClassLoader.getSystemClassLoader() , если это значение равно null.

Как только у вас есть экземпляр класса, вы можете получить его конструкторы через getDeclaredConstructor(...) . Итак, если у вас есть public class MyClass с таким конструктором, как public MyClass(String) { ... } тогда

 Class<MyClass> clazz = MyClass.class;
Constructor<MyClass> ctor = clazz.getDeclaredConstructor(String.class);
MyClass instance = ctor.newInstance("foo");
  

вышесказанное игнорирует множество возможных исключений.

Комментарии:

1. является ли MyClass экземпляром или статической ссылкой на класс? Могу ли я каким-либо образом получить конструктор класса, передав его имя в виде строки методу? Или каким-либо другим способом, аналогичным этому?

2. MyClass это имя класса в этом примере. Класс может иметь несколько конструкторов (или ни одного для интерфейсов); для класса не существует «конструктора».

3. MyClass.class Синтаксис может сбивать с толку. Это просто способ обращения к экземпляру класса для MyClass . Так String.class.isInstance(x) можно сказать по-другому x instanceof String .

4. как мне создать экземпляр без фактического жесткого кодирования имени класса? Я хочу загрузить класс, передав строку функции, и она сконструирует и создаст экземпляр объекта этого класса.

5. @rubixibuc, Class<?> clazz = myClassLoader.loadClass(className) как описано в первом абзаце.

Ответ №3:

Вот что у меня получилось. Это не готовый продукт, а просто тест, чтобы посмотреть, смогу ли я заставить его работать. Спасибо всем, кто ответил на запрос :-).

 public class SimLoader {  
  public static void main(String[] args)  
  {  
    try {  
      Object simulator = Class.forName("SimX").newInstance();  
      ((SimInterface)simulator).run();  
    }  
    catch(ClassNotFoundException e) {}  
    catch(InstantiationException e) {}  
    catch(IllegalAccessException e) {}  
  }  
}

interface SimInterface {  
 void run();  
} 

class SimX implements SimInterface  
{  
  public void run() {  
    System.out.println("Success");  
  }  
}  
  

Комментарии:

1. Лучшее решение для меня. Но не забудьте использовать FullyQualifiedName для класса (например, com.mycomapy.SimX, в вашем примере, возможно, не требуется).

2. Откуда берется (SimInterface)? Компилятор Java 11 не может найти этот символ. Как это можно использовать?