Слабая связь с Class.forName()

interface Bank {
    void connect();
}

class SBI implements Bank {
    static{
        System.out.println("Hello from SBI static");
    }   
    public void connect() {
        System.out.println("Connected to SBI");
    }
}

class LooseCouplingTest {
    public static void main(String... args)throws Exception {
        String className = args[0];
        Class.forName(className);
    }
}

Вывод приведенного выше кода выглядит следующим образом:
Hello from SBI static

Что я должен добавить в свой код и Y, чтобы also напечатать оператор
Connected to SBI

Подробное объяснение очень ценится

P.S. Нуб здесь


person Testaccount    schedule 14.04.2013    source источник


Ответы (2)


Вы должны создать новый экземпляр объекта (используя Class#newInstance()), привести его к нужному типу (в вашем сценарии SBI), а затем вызвать его.

Рабочий код:

public class LooseCouplingTest {
    public static void main(String... args)throws Exception {
        String className = args[0];
        Class<?> clazz = Class.forName(className);
        Object obj = clazz.newInstance();
        SBI mySBI = (SBI) obj;
        mySBI.connect();
    }
}

Пояснение:

  • Class.forName("pkg.SBI") получает ссылку на класс pkg.SBI в объекте clazz.
  • Поскольку clazz содержит ссылку на SBI, вызов clazz.newInstance(); аналогичен вызову: new SBI();.
  • После вызова clazz.newInstance(); переменная obj получит экземпляр SBI.
  • Поскольку вы хотите вызвать метод SBI, а тип obj равен Object (это тип возвращаемого значения метода newInstance()), вы должны привести его к SBI и только потом вызывать connect().

Используя Java Reflection API:

Если вы хотите пойти еще дальше и даже не выполнять приведение (таким образом LooseCouplingTest никогда не нужно импортировать SBI), вы можете использовать Java Reflection API для вызова метода connect().

Вот рабочий код для этого:

public class LooseCouplingTest {
    public static void main(String... args) throws Exception {
        String className = args[0];
        Class<?> clazz = Class.forName(className);
        Object obj = clazz.newInstance();
        java.lang.reflect.Method connect = clazz.getMethod("connect");
        connect.invoke(obj);
    }
}
person acdcjunior    schedule 14.04.2013
comment
@abcdjunior Спасибо за ваше время .. можете ли вы дать пошаговое объяснение того, почему мы должны создавать новый экземпляр объекта (используя Class#newInstance()), приводить его к нужному типу, а затем вызывать???? ????? - person Testaccount; 14.04.2013
comment
@SnackySrikanth Да: Class.forName("pkg.SBI") получает ссылку на класс pkg.SBI в объекте clazz. Поскольку clazz содержит ссылку на SBI, вызов clazz.newInstance(); аналогичен вызову: new SBI();. После вызова clazz.newInstance(); переменная obj получит экземпляр SBI. Наконец, поскольку вы хотите вызвать метод SBI, а тип objObject (это тип возвращаемого значения метода newInstance()), вы должны привести его к SBI и только затем вызвать connect(). (Я отредактировал ответ, чтобы включить это. Дайте мне знать, достаточно ли этого.) - person acdcjunior; 15.04.2013

Class.forName() загружает класс. и часть загрузки класса выполняет блок статического инициализатора. Вот почему вы видите напечатанное «Hello from SBI static» (часть static { ... } — это статический блок инициализатора).

Чтобы появилось «Подключено к SBI», вам нужно создать экземпляр класса и вызвать для него метод connect():

Class<? extends Bank> bankClass = (Class<? extends Bank>)Class.forName(className);
Bank bank = bankClass.newInstance();
bank.connect();
person Jesper    schedule 14.04.2013