简体   繁体   中英

Passing class name as parameter

I have 3 classes called RedAlert , YellowAlert , and BlueAlert .

Within my class AlertController I want to have a method like this:

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

So for example I want to:

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

How do you take in the class name as a parameter, and based on that class name create the appropriate object from the class name?

Using reflection it is possible. Here for a given className (passed as a string) . This class will be searched in memory ( it should be already loaded).

The name of the class to be instantiated when passed as a string should be fully qualified

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


        Class classTemp = Class.forName(className);

        Object obj =classTemp.newInstance();



    }
}

Instead of passing the class name, you can pass the class itself and use reflection to create a new instance of the class. Here's a basic example (assuming all your XxxAlert classes extend from an Alert class):

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

Now you just call the method like this:

setAlert(RedAlert.class);

Note that it would be better using a super class in T parameter, otherwise you (or another programmer) could do this:

setAlert(Object.class);

which would be plain wrong.

While you can create it using Reflection etc... I'd suggest investigating some Creational Design Patterns.

Specifically the Factory Pattern

Here is a (very) crude example:

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

And then from your Method you could use:

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

Anyway, while this is a really ugly example, I'm trying to highlight that maybe you could look at the Creational Patterns and solve your problem a different way without passing classnames around.

Why not use a factory pattern approach.

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

Then you could do something like this.

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

It's possible to use your approach using java.lang.Class#newInstance .

You can have a reference of Class in your method signature, something like this:

public void SetAlert(Class class)

Then in your method you can create the instance of the input class using the newInstance method:

Object obj = class.newInstance();

What about this -

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

避免内部依赖和初始化:

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

Use enums:

public enum AlertType {RED_ALERT, YELLOW_ALERT, BLUE_ALERT};

// ...

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

// ...

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

Many options:

  1. Look at standard factory approach: http://en.wikipedia.org/wiki/Factory_method_pattern
  2. Use enum instead of the class enum Alert{Red, Yellow, Green;}

Use Java Reflection to create object from Class object. Declare your method like this:

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

And then,

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

This is the way to create an instance using a class name. The concrete type of Alert must have a public constructor that takes no arguments.

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

The caller would use it like this:

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

If you create a convention for passing a certain set of parameters to the constructor, you can do that too, but you'll need to do a little extra work in the getConstructor() call to find it. You can also use constructors that aren't public, but, again, that takes a bit of extra work.

The suggestions to pass the class literal, RedAlert.class , don't make much sense. If the RedAlert class is available to the caller at compile time, you'd just use its constructor, new RedAlert() .

Another way you can do this without using reflection is to have an Interface say Alert and have your classes - RedAlert, YellowAlert, and BlueAlert implement the Alert interface.
So now your method in AlertController looks like:

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

Now you can do :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM