Java 将类名作为参数传递

Java 将类名作为参数传递,java,Java,我有三个类,分别是RedAlert、YellowAlert和BlueAlert 在我的类AlertController中,我希望有这样一个方法: public void SetAlert(//TAKE IN NAME OF CLASS HERE//) { CLASSNAME anInstance = new CLASSNAME(); } public void SetAlert(Class class) setAlert(RedAlert.class); public void S

我有三个类,分别是
RedAlert
YellowAlert
BlueAlert

在我的类
AlertController
中,我希望有这样一个方法:

public void SetAlert(//TAKE IN NAME OF CLASS HERE//)
{
    CLASSNAME anInstance = new CLASSNAME();
}
public void SetAlert(Class class)
setAlert(RedAlert.class);
public void SetAlert(Class clazz)
{
    Constructor<?> ctor = clazz.getConstructor();
    Object object = ctor.newInstance();
}
AlertController aController = new AlertController();
controller.setAlert("com.y.foo.RedAlert");
例如,我想:

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

如何将类名作为参数,并基于该类名从类名创建适当的对象?

您可以在方法签名中引用类,如下所示:

public void SetAlert(//TAKE IN NAME OF CLASS HERE//)
{
    CLASSNAME anInstance = new CLASSNAME();
}
public void SetAlert(Class class)
setAlert(RedAlert.class);
public void SetAlert(Class clazz)
{
    Constructor<?> ctor = clazz.getConstructor();
    Object object = ctor.newInstance();
}
AlertController aController = new AlertController();
controller.setAlert("com.y.foo.RedAlert");
然后在方法中,可以使用newInstance方法创建输入类的实例:

Object obj = class.newInstance();

避免内部依赖关系和初始化:

AlertController aController = new AlertController(new RedAlert());
这个怎么样-

public void SetAlert(Class<?> class){
     Object obj = class.newInstance();
     if(obj isInstanceOf RedAlert){
         RedAlert ra= (RedAlert)obj;
     }
     ...
}
public void SetAlert(类){
Object obj=class.newInstance();
如果(obj isInstanceOf REDARTER){
红色警报ra=(红色警报)obj;
}
...
}

而您可以使用反射等创建它。。。我建议调查一些创造性的设计模式

特别是工厂模式

下面是一个(非常)粗糙的例子:

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;
    }
}

无论如何,虽然这是一个非常丑陋的例子,但我想强调的是,也许你可以看看创造性模式,用不同的方式解决你的问题,而不需要传递类名。

你可以传递类本身,并使用反射来创建类的新实例,而不是传递类名。下面是一个基本示例(假设所有
XxxAlert
类都是从
Alert
类扩展而来):

请注意,最好在
T
参数中使用一个超类,否则您(或其他程序员)可以这样做:

setAlert(Object.class);

这显然是错误的。

使用反射是可能的。这里是一个给定的类名(作为字符串传递)。该类将在内存中搜索(应该已经加载)

作为字符串传递时要实例化的类的名称应该是完全限定的

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


        Class classTemp = Class.forName(className);

        Object obj =classTemp.newInstance();



    }
}
使用枚举:

public enum AlertType {RED_ALERT, YELLOW_ALERT, BLUE_ALERT};

// ...

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

// ...

AlertController aController = new AlertController();
SetAlert(AlertType.RED_ALERT);
有很多选择:

  • 看看标准工厂方法:
  • 使用enum而不是类enum Alert{Red,Yellow,Green;}

  • 使用Java反射从类对象创建对象。如下所示声明您的方法:

    public void SetAlert(//TAKE IN NAME OF CLASS HERE//)
    {
        CLASSNAME anInstance = new CLASSNAME();
    }
    
    public void SetAlert(Class class)
    
    setAlert(RedAlert.class);
    
    public void SetAlert(Class clazz)
    {
        Constructor<?> ctor = clazz.getConstructor();
        Object object = ctor.newInstance();
    }
    
    AlertController aController = new AlertController();
    controller.setAlert("com.y.foo.RedAlert");
    

    这是使用类名创建实例的方法。
    警报的具体类型必须具有不带参数的公共构造函数

    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);
      }
    }
    
    如果您创建了一个将某组参数传递给构造函数的约定,您也可以这样做,但是您需要在
    getConstructor()
    调用中做一些额外的工作才能找到它。您也可以使用非公共的构造函数,但是,同样,这需要一些额外的工作


    传递类文本的建议,
    RedAlert.class
    ,没有多大意义。如果调用方在编译时可以使用
    RedAlert
    类,则只需使用其构造函数
    new RedAlert()

    另一种不使用反射的方法是使用一个接口say Alert,并让您的类RedAlert、YellowAlert和BlueAlert实现警报接口
    现在,您在AlertController中的方法如下所示:

    public void setAlert(Alert alert) {
           // Your code goes here
    }
    
    现在您可以执行以下操作:

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

    为什么不使用工厂模式方法呢

    公共接口警报{}
    公共类RedAlert实现警报{}
    公共类YellowAlert实现警报{}
    公共类BlueAlert实现警报{}
    公共接口警报工厂{
    警报创建();
    }
    公共类RedAlertFactory实现AlertFactory{
    公共警报创建(){
    返回新的RedAlert();
    }
    }
    公共类YellowAlertFactory实现AlertFactory{
    公共警报创建(){
    返回新的YellowAlert();
    }
    }
    公共类BlueAlertFactory实现AlertFactory{
    公共警报创建(){
    返回新的BlueAlert();
    }
    }
    //您的setAlert方法可能如下所示
    公共无效设置警报(警报工厂){
    aInstance=工厂->创建();
    }
    
    然后你可以做这样的事情。


    可以使用您的方法。

    您需要查看Java反射API!但你为什么想要它?
    SetAlert(new RedAlert())
    有什么问题?@edwardsmatt这是我答案的一部分,否则OP可能会犯错误,在大多数情况下使用Object.class(或任何其他类)调用上一个示例中所示的方法,这比公认的答案要好。通过使用
    equals
    而不是
    =
    并按照您在开始时建议的使用反射,可以大大改进此工厂。否则,想象一下当新的
    Alert
    子类出现时会发生什么。我完全同意!很难确切知道用例是什么,在本例中,您应该只传入实例化的对象。@raniejade的答案是比这个更干净的工厂设计。这里的答案使用了if测试的非OO方法。raniejade使用工厂的子类化。注意:每个工厂只需要一个副本。如果AlertFactory是一个类而不是一个接口,那么它可以包含静态变量,每个工厂一个<代码>公共抽象类AlertFactory{…public readonly static RedAlertFactory red=new RedAlertFactory();…}
    则无需在每次使用时创建新工厂:
    setAlert(AlertFactory.red)