簡體   English   中英

將類名作為參數傳遞

[英]Passing class name as parameter

我有3個名為RedAlertYellowAlertBlueAlert

在我的類AlertController我希望有一個像這樣的方法:

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

所以例如我想:

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

如何將類名作為參數,並根據該類名從類名創建適當的對象?

使用反射是可能的。 這里是給定的className(作為字符串傳遞)。 將在內存中搜索此類(它應該已經加載)。

作為字符串傳遞時要實例化的類的名稱應該是完全限定的

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


        Class classTemp = Class.forName(className);

        Object obj =classTemp.newInstance();



    }
}

您可以傳遞類本身並使用反射來創建類的新實例,而不是傳遞類名。 這是一個基本示例(假設您的所有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);

這是完全錯誤的。

雖然您可以使用Reflection等創建它...我建議調查一些創建設計模式。

特別是工廠模式

這是一個(非常)粗略的例子:

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並以不同的方式解決你的問題而不傳遞類名。

為什么不使用工廠模式方法。

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

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

public void SetAlert(Class class)

然后在您的方法中,您可以使用newInstance方法創建輸入類的實例:

Object obj = class.newInstance();

那這個呢 -

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

避免內部依賴和初始化:

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

使用枚舉:

public enum AlertType {RED_ALERT, YELLOW_ALERT, BLUE_ALERT};

// ...

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

// ...

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

很多選擇:

  1. 看看標准工廠方法: http//en.wikipedia.org/wiki/Factory_method_pattern
  2. 使用枚舉而不是類枚舉Alert {Red,Yellow,Green;}

使用Java Reflection從Class對象創建對象。 像這樣聲明你的方法:

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

然后,

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

這是使用類名創建實例的方法。 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()

另一種不使用反射就可以做到這一點的方法是讓一個接口說出Alert並讓你的類--RedAlert,YellowAlert和BlueAlert實現Alert接口。
所以現在你在AlertController中的方法看起來像:

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

現在你可以這樣做:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM