17

我有 3 个类,分别称为RedAlertYellowAlertBlueAlert

在我的课堂AlertController上,我想要一个这样的方法:

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

所以例如我想:

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

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

4

12 回答 12

23

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

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

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


        Class classTemp = Class.forName(className);

        Object obj =classTemp.newInstance();



    }
}
于 2013-07-25T05:09:33.103 回答
20

您可以传递类本身并使用反射来创建该类的新实例,而不是传递类名。这是一个基本示例(假设您的所有类都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);

这是完全错误的。

于 2013-07-25T05:07:58.590 回答
2

虽然您可以使用反射等创建它...我建议调查一些创建设计模式。

特别是工厂模式

这是一个(非常)粗略的例子:

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

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

于 2013-07-25T05:07:53.387 回答
2

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

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使用您的方法。

于 2013-07-25T05:18:59.267 回答
1

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

public void SetAlert(Class class)

然后在您的方法中,您可以使用 newInstance 方法创建输入类的实例:

Object obj = class.newInstance();
于 2013-07-25T05:04:25.070 回答
1

那这个呢 -

public void SetAlert(Class<?> class){
     Object obj = class.newInstance();
     if(obj isInstanceOf RedAlert){
         RedAlert ra= (RedAlert)obj;
     }
     ...
}
于 2013-07-25T05:06:28.720 回答
0

避免内部依赖和初始化:

AlertController aController = new AlertController(new RedAlert());
于 2013-07-25T05:05:56.193 回答
0

使用 Java 反射从 Class 对象创建对象。像这样声明你的方法:

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

接着,

 AlertController aController = new AlertController();
    SetAlert(RedAlert.class);
于 2013-07-25T05:15:54.050 回答
0

这是使用类名创建实例的方法。的具体类型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().

于 2013-07-25T05:16:12.473 回答
0

使用枚举:

public enum AlertType {RED_ALERT, YELLOW_ALERT, BLUE_ALERT};

// ...

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

// ...

AlertController aController = new AlertController();
SetAlert(AlertType.RED_ALERT);
于 2013-07-25T05:10:21.113 回答
0

很多选择:

  1. 查看标准工厂方法: http ://en.wikipedia.org/wiki/Factory_method_pattern
  2. 使用枚举而不是类枚举 Alert{Red, Yellow, Green;}
于 2013-07-25T05:12:02.273 回答
0

不使用反射的另一种方法是让接口说 Alert 并让您的类 - RedAlert、YellowAlert 和 BlueAlert 实现 Alert 接口。
所以现在你在 AlertController 中的方法看起来像:

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

现在你可以这样做:

setAlert(new RedAlert());
setAlert(new YellowAlert());
setAlert(new BlueAlert());
于 2013-07-25T05:18:09.997 回答