Подтвердить что ты не робот

Разница между вызовом конструктора класса и использованием Class.forName(). NewInstance

Я пытался понять разницу между использованием new для создания объекта с помощью Class.forName("A").newInstance();.

Я выполнил следующий код для простого класса A, который показывает, что использование Class.forname("A").newInstance() в 70-100 раз медленнее, чем просто new A().

Мне любопытно узнать, почему такая разница во времени, но не могла понять. Пожалуйста, помогите мне понять причину.

public class Main4test {

    public Main4test() {
    }

    static int turns = 9999999;

    public static void main(String[] args) {
        new Main4test().run();
    }

    public void run() {
        System.out.println("method1: " + method1() + "");
        System.out.println("method2:" + method2() + "");
    }

    public long method2() {
        long t = System.currentTimeMillis();
        for (int i = 0; i < turns; i++) {
            try {
                A a = (A) Class.forName("A").newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return System.currentTimeMillis() - t;
    }

    public long method1() {
        long t = System.currentTimeMillis();
        for (int i = 0; i < turns; i++) {
            try {
                A a = new A();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return System.currentTimeMillis() - t;
    }

}

public class A {
    int a;
    public A() {
    a=0;
    }
}
4b9b3361

Ответ 1

A a = new A();

Вызывает оператор new и конструктор A напрямую, где A упоминается в исходном тексте и поэтому уже загружен и инициализирован.

A a = (A) Class.forName("A").newInstance();
  • Посмотрите, была ли загружена A
  • загрузите его при необходимости
  • при необходимости инициализировать его
  • найдите конструктор no-args через отражение
  • вызовите оператор new и конструктор no-args через отражение
  • введите результат A

Ответ 2

Использование отражения Class.forName("A").newInstance(); - это не только дорогостоящая операция (потому что правильному загрузчику классов необходимо делегировать и загружать класс во время выполнения), но также делает ваш код более сложным для отладки, и вы теряете все преимущества (что происходит во время компиляции).

Вывод:
Избегайте отражения, если вы не должны использовать его (например, если вы пишете плагин/библиотеку, ориентированную на аспект)

Ответ 3

Разница между оператором new и newInstance приведена ниже:

  • новый оператор может использоваться с любым конструктором класса, передавая любое количество аргументов, принятое конструктором. Метод newInstance требует наличия конструктора no-arg в классе, для которого он был вызван. Если вы хотите использовать конструктор с newInstance, вам нужно получить экземпляр класса Constructor для любого конструктора, а затем вызвать newInstance, например:

    Class class = Class.forName("A");  
    Constructor const = class.getConstructor(A.class);  
    A a = null;  
    const.newInstance(a);
  • Использование нового оператора не требует явной загрузки классов, поскольку он управляется JVM внутри компании. Для метода newInstance() требуется экземпляр класса Class (Class.forName( "A" ). NewInstance() или как показано в приведенной выше точке). Объект класса, относящийся к базовому классу, получается путем вызова метода forName.

  • Использование нового оператора рекомендуется, когда имя класса известно во время компиляции. Поскольку newInstance использует отражение для создания объекта класса, его рекомендуется использовать, когда класс неизвестен во время компиляции, но определяется во время выполнения.

  • Поскольку в новом операторе нет дополнительной обработки, связанной с вызовом метода, например forName, она быстрее, чем newInstance. Использование newInstance приводит к дополнительной обработке на части JVM (проверки типов, проверки безопасности) и, следовательно, не рекомендуется использовать для ухудшения производительности. (По крайней мере, когда тысячи экземпляров создаются с использованием newInstance)

  • Все разработчики Java должны знать нового оператора, поскольку это базовая концепция, которая изучается на уровне начинающих, поэтому нет ничего особенного, чтобы узнать об этом. Не все разработчики, работающие над приложением, должны быть осведомлены об отражении, и, следовательно, есть кривая обучения для начинающих, работающих над кодом с помощью метода newInstance.

  • Вы можете видеть, что новый оператор используется в любой нормальной программе Java. newInstance используется во многих местах внутри Java, особенно на стороне сервера, таких как загрузка и создание экземпляров сервлетов, апплетов, шлейфов/скелетов JNDI, драйверов базы данных JDBC.

  • С новым оператором загрузка классов и создание объектов выполняется загрузчиком классов по умолчанию JDK. Но с помощью метода newInstance можно явно указать загрузчик классов, который будет использоваться для загрузки экземпляра класса и объекта.

  • Есть меньше шансов на исключение во время выполнения с новым оператором. Только редкий случай, когда класс присутствовал во время компиляции, но не был доступен по пути класса во время выполнения. Использование метода newInstance с Class.forName(String...) может привести к исключению во время выполнения, даже если имя класса, переданное как аргумент метода forName, недействительно.

  • Использование нового оператора приводит к генерации соответствующего байтового кода в файле .class. Когда используется newInstance, нет дополнительного байтового кода, сгенерированного для создания объекта внутри класса, поскольку создание объекта обрабатывается динамически.

  • С новым оператором существует встроенная проверка типов, а ошибка компилятора отображается, если класс не существует. Поскольку имя класса передается в качестве аргумента в метод Class.forName как строку, проверка типа компиляции не выполняется и обычно приводит к исключению времени выполнения, как описано в одной из предыдущих точек.

Ссылка: http://www.javaexperience.com/difference-between-new-operator-and-class-forname-newinstance/

Ответ 4

Основное отличие между традиционными new и newInstance заключается в том, что newInstance позволяет гибко создавать экземпляр класса, который вы не знаете до выполнения, и делает ваш код более динамичным. Когда класс неизвестен до выполнения, тогда это действительный случай, когда вы должны использовать отражение.

Из Javadoc вызов Class.forName(String) возвращает объект класса, связанный с классом или интерфейсом с заданным именем строки, то есть возвращает Класс A

Итак, A a = (A) Class.forName("A").newInstance() разбивается на:

  • Class.forName("A")
    возвращает класс A класса Class.

  • Class.forName("A").newInstance() Создает новый экземпляр класса, представленного этим объектом класса, поэтому вы получаете экземпляр типа A. Класс создается таким образом, как будто новым выражением с пустым списком аргументов. Класс инициализируется, если он еще не был инициализирован. Это здесь фактически эквивалентно новому A() и возвращает новый экземпляр A.

    Важно: Использование этого метода эффективно обходит проверку исключения времени компиляции, которая в противном случае была бы выполнена компилятором.

Справка:

Ответ 5

Тест, который вы используете для измерения скорости, не является допустимым тестом. Производительность Java очень сложна и включает в себя hotspot vm, умные компиляторы и сборщики мусора, чтобы начать с.

В методе 1 java обычно будет достаточно умным, чтобы сделать только один экземпляр A в памяти и повторно использовать его для каждой итерации

в методе 2 вы вынуждаете виртуальную машину использовать рефлексию и загрузчики классов для создания объекта. что само по себе уже медленнее