2015-09-28 5 views
1

Я нашел этот код внутри старого проектавернуть Class.forName вместо нового экземпляра

public abstract class AireBatchDaoFactory { 
    public static final String ORACLE_FACTORY = "airebatch.oracle.OracleDaoFactory"; 
    public static AireBatchDaoFactory getFactory(String factory) throws SQLException 
    { 
     try { 
      return (AireBatchDaoFactory) Class.forName(factory).newInstance(); 
     } 
     catch (Exception e) { 
      throw new SQLException("error msg"); 
     } 
    } 
    public abstract AireBatchDao getAireBatchDao() throws SQLException;} 

Я хотел бы понять конкретную разницу Разногласия между

return (AireBatchDaoFactory) Class.forName(factory).newInstance(); 

и

return new AireBatchDaoFactory(); 
+0

Это называется ** отражение **. Существует строка 'String', описывающая FQCN' class', и код пытается преобразовать этот 'String' сначала в экземпляр класса, а затем в новый экземпляр этого' class', предполагая конструктор по умолчанию. Это ** только ** способ создания экземпляра из 'String' -' new', очевидно, не будет работать здесь. –

+0

Написание только 'return class.forName (factory) .newInstance();' могло быть общим, остальное кажется таким же. Кроме того, захватывая супер 'Exception' и бросая' SQLException' вместо 'ClassNotFoundException', возможно, кто-то изменил бы это в течение определенного периода времени. Даже без использования переменной 'ORACLE_FACTORY' –

+0

Кроме того, обычно эти заводы являются _abstract classes_ (как и в вашем случае), которые не могут быть созданы. Бросок необходим для выполнения подписи метода (а также может быть неудачным). – Seelenvirtuose

ответ

2

Внимательно посмотрите на метод

getFactory(String factory) 

Вы получаете имя класса в качестве параметра. Вы не можете написать

factory factory = new factory(); // error. 

Где

Class.forName(factory).newInstance(); 

Является действительным.

Короче говоря, вы создаете экземпляр класса, используя его имя, которое вы не делаете во время компиляции, и создаете экземпляр во время выполнения с переданным именем, используя Reflection.

4

Разница заключается в том, что new AireBatchDaoFactory создаст экземпляр , что конкретный класс (или не компилировать, если AireBatchDaoFactory является интерфейсом или абстрактным классом). Но factory может содержать полное имя любого класса, который реализует AireBatchDaoFactory (если это интерфейс) или подклассы его (если это класс). Class.forName(factory).newInstance() загрузит класс с именем factory и создаст его новый экземпляр.

Это довольно распространенный шаблон для плагинов времени выполнения для кодовой базы. Обычно вы определяете интерфейс, который реализуют плагины. Затем вы предоставляете средство времени выполнения для указания того, какой конкретный класс использовать (в файле свойств, в некоторых других конфигурациях и т. Д.), И используйте Class.forName для загрузки класса и newInstance для создания экземпляра его. Поскольку класс определяется по адресу runtime, это может быть то, что авторы использующего его кода никогда не видели, написаны долго после кода, который его использует. Следовательно, используя его для плагинов.

Рассмотрим:

Plugin.java:

interface Plugin { 
    void doSomething(); 
} 

Foo.java:

public class Foo implements Plugin { 
    public void doSomething() { 
     System.out.println("I'm Foo"); 
    } 
} 

Bar.java:

public class Bar implements Plugin { 
    public void doSomething() { 
     System.out.println("I'm Bar"); 
    } 
} 

App.java:

public class App { 

    public static final void main(String[] args) { 
     try { 
      String classToLoad = args[0]; 
      Plugin plugin = Class.forName(classToLoad).newInstance(); 
      plugin.doSomething(); 
     } 
     catch (Exception e) { 
      //...handle error... 
     } 
    } 
} 

Запуск

 
java App Foo 

...загружает класс Foo и звонит doSomething, давая нам "I'm Foo".

Запуск

 
java App Bar 

... загружает Bar класс и вызывает doSomething на него, давая нам "I'm Bar".

1

Вы не можете позвонить в new AireBatchDaoFactory() для абстрактного класса. В вашем примере отражение используется для получения экземпляра класса с именем, которое передается как параметр метода getFactory. Этот класс должен расширять абстрактный класс AireBatchDaoFactory.

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

Смежные вопросы