Передача имени класса в качестве параметра

У меня есть 3 класса, называемые RedAlert, YellowAlert и BlueAlert.

В моем классе AlertController я хочу иметь такой метод:

public void SetAlert(//TAKE IN NAME OF CLASS HERE//)
{
    CLASSNAME anInstance = new CLASSNAME();
}

Так, например, я хочу:

AlertController aController = new AlertController();
SetAlert(RedAlert);

Как взять имя класса в качестве параметра и на основе этого имени класса создать соответствующий объект из имени класса?

Ответ 1

Использование отражения возможно. Здесь для данного классаName (проходит как строка). Этот класс будет искать в памяти (он должен быть уже загружен). Имя класса, создаваемого при передаче в виде строки, должно быть полностью квалифицированным

void createInstanceOfClass(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException{


        Class classTemp = Class.forName(className);

        Object obj =classTemp.newInstance();



    }
}

Ответ 2

Вместо передачи имени класса вы можете передать сам класс и использовать отражение для создания нового экземпляра класса. Вот базовый пример (предполагая, что все ваши классы XxxAlert простираются от класса Alert):

public <T extends Alert> void setAlert(Class<T> clazzAlert) {
    Alert alert = clazzAlert.newInstance();
    //use the alert object as you want/need...
}

Теперь вы просто вызываете метод следующим образом:

setAlert(RedAlert.class);

Обратите внимание, что лучше было бы использовать суперкласс в параметре T, иначе вы (или другой программист) могли бы сделать это:

setAlert(Object.class);

что было бы неправильно.

Ответ 3

Пока вы можете создать его с помощью Reflection и т.д. Я бы предложил исследовать некоторые шаблоны проектирования Creation.

В частности, шаблон Factory

Вот (очень) грубый пример:

public interface Alert {
}


public class BlueAlert implements Alert {
}

public class RedAlert implements Alert {
}

public class YellowAlert implements Alert {
}

public final class AlertFactory {

    public <T extends Alert> Alert create(Class<T> clazz) {
        Alert toReturn = null;
        if (RedAlert.class.equals(clazz)) {
            toReturn = new RedAlert();
        } else if (YellowAlert.class.equals(clazz)) {
            toReturn = new YellowAlert();
        } else if (BlueAlert.class.equals(clazz)) {
            toReturn = new BlueAlert();
        }
        return toReturn;
    }
}

И затем из вашего метода вы можете использовать:

public void SetAlert(Class alertClass) { 
    Alert theAlert = new AlertFactory().create(alertClass);
}

В любом случае, хотя это действительно уродливый пример, я пытаюсь подчеркнуть, что, возможно, вы могли бы посмотреть на Creational Patterns и решить свою проблему по-другому, не передавая классные имена.

Ответ 4

Почему бы не использовать шаблонный шаблон factory.

public interface Alert {}

public class RedAlert implements Alert {}
public class YellowAlert implements Alert {}
public class BlueAlert implements Alert {}

public interface AlertFactory {
    Alert create();
}

public class RedAlertFactory implements AlertFactory {
    public Alert create() {
        return new RedAlert();
    }
}

public class YellowAlertFactory implements AlertFactory {
    public Alert create() {
        return new YellowAlert();
    }
}

public class BlueAlertFactory implements AlertFactory {
    public Alert create() {
        return new BlueAlert();
    }
}

// your setAlert method could probably look like this
public void setAlert(AlertFactory factory) {
    aInstance = factory->create();
}

Тогда вы могли бы сделать что-то вроде этого.

setAlert(new RedAlertFactory()); // or YellowAlertFactory, BlueAlertFactory

Можно использовать ваш подход, используя java.lang.Class # newInstance.

Ответ 5

У вас может быть ссылка класса в вашей сигнатуре метода, что-то вроде этого:

public void SetAlert(Class class)

Затем в вашем методе вы можете создать экземпляр класса ввода с помощью метода newInstance:

Object obj = class.newInstance();

Ответ 6

Как насчет этого -

public void SetAlert(Class<?> class){
     Object obj = class.newInstance();
     if(obj isInstanceOf RedAlert){
         RedAlert ra= (RedAlert)obj;
     }
     ...
}

Ответ 7

Избегайте внутренних зависимостей и инициализаций:

AlertController aController = new AlertController(new RedAlert());

Ответ 8

Использовать перечисления:

public enum AlertType {RED_ALERT, YELLOW_ALERT, BLUE_ALERT};

// ...

public void SetAlert(AlertType type)
{
    // ...
}

// ...

AlertController aController = new AlertController();
SetAlert(AlertType.RED_ALERT);

Ответ 9

Много вариантов:

  • Посмотрите на стандартный подход factory: http://en.wikipedia.org/wiki/Factory_method_pattern
  • Использовать перечисление вместо атрибута перечисления класса {Red, Yellow, Green;}

Ответ 10

Используйте Java Reflection для создания объекта из объекта класса. Объявите свой метод следующим образом:

public void SetAlert(Class clazz)
{
    Constructor<?> ctor = clazz.getConstructor();
    Object object = ctor.newInstance();
}

И затем,

 AlertController aController = new AlertController();
    SetAlert(RedAlert.class);

Ответ 11

Это способ создания экземпляра с использованием имени класса. Конкретный тип Alert должен иметь открытый конструктор, который не принимает аргументов.

private Alert alert;

public void setAlert(String className) 
{
  try {
    Class<?> raw = Class.forName(className);
    Class<? extends Alert> type = raw.asSubclass(Alert.class);
    Constructor<? extends Alert> ctor = type.getConstructor();
    this.alert = ctor.newInstance();
  } catch (Exception ex) {
    throw new IllegalArgumentException("Invalid Alert implementation.", ex);
  }
}

Звонящий будет использовать его следующим образом:

AlertController aController = new AlertController();
controller.setAlert("com.y.foo.RedAlert");

Если вы создаете соглашение о передаче определенного набора параметров конструктору, вы также можете это сделать, но вам нужно сделать небольшую дополнительную работу в вызове getConstructor(), чтобы найти его. Вы также можете использовать конструкторы, которые не являются общедоступными, но, опять же, это требует немного дополнительной работы.

Предложения о передаче литерала класса RedAlert.class не имеют большого смысла. Если класс RedAlert доступен для вызывающего во время компиляции, вы просто используете его конструктор new RedAlert().

Ответ 12

Другой способ, которым вы можете это сделать, не используя рефлексию, - это использовать интерфейс "Оповещение" и иметь свои классы - RedAlert, YellowAlert и BlueAlert реализовать интерфейс Alert.
Итак, теперь ваш метод в AlertController выглядит так:

public void setAlert(Alert alert) {
       // Your code goes here
}

Теперь вы можете сделать:

setAlert(new RedAlert());
setAlert(new YellowAlert());
setAlert(new BlueAlert());