Java反射 獲得Class對象的五種方法

class building {}

class Maker<T> {
    Class<T> kind;
    Maker(Class<T> kind){
        this.kind = kind;
    }
    T make() throws IllegalAccessException, InstantiationException {
        return kind.newInstance();
    }
}

public class test {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        /*第一種方式*/
        Class<?> fromFroName = Class.forName("building");
        // Class<? extends building> fromFroName2 = Class.forName("building");  //解開註釋,編譯報錯
        // Class<building> fromFroName3 = Class.forName("building");  //解開註釋,編譯報錯

        /*第二種方式*/
        Class<? extends building> fromGetClass = new building().getClass();
        // Class<building> fromGetClass2 = new building().getClass();  //解開註釋,編譯報錯

        /*第三種方式*/
        Class<building> fromClass = building.class;

        /*第四種方式*/
        ClassLoader loader = new building().getClass().getClassLoader();
        Class<?> fromLoadClass = loader.loadClass("building");

        /*第五種方式*/
        Maker<building> maker = new Maker<building>(fromClass);
        Class<building> fromMakerKind = maker.kind;
        building b = maker.make();
    }
}
  1. 通過Class.forName(類名)獲得。但這種方式獲得的Class對象的泛型類型只能是通配符的,從下面的兩行註釋代碼可知,要想獲得更具體的泛型類型時,都會編譯報錯。
  2. 通過對象.getClass()獲得。這種方式獲得的Class對象的泛型類型,雖然比上一種更加具體,可以是Class<? extends building>了,但不能具體到Class<building>了。
  3. 通過類名.class獲得。這種方式獲得的Class對象的泛型類型,最具體,是Class<building>
  4. 通過ClassLoader對象.loadClass("類名")獲得。但這種方式獲得的Class對象,和第一種Class.forName(類名)一樣,只能是通配符的泛型類型。
  5. 通過成員變量Class<T> kind獲得,注意Maker是一個自定義的泛型類(第五種其實和反射無關了)。因爲泛型指定了new Maker<building>,所以構造器實際上變成了Maker(Class<building> kind),而對於傳入的fromClass而言,是符合構造器參數類型。不用擔心泛型機制的類型擦除會擦除掉Class<T> kind裏的尖括號裏的信息,因爲在泛型代碼的出口處(比如maker.kind)會自動強轉爲ClassClass<building>

關於第五種方式,還可以進行拓展,但需要理解泛型的相關知識:

        Class<building> fromMakerKind1 = new Maker<building>(fromClass).kind;

        // Class<building> fromMakerKind2 = new Maker<? extends building>(fromGetClass).kind;
        Class<building> fromMakerKind2 = new Maker(fromGetClass).kind;
        
        // Class<building> fromMakerKind3 = new Maker<?>(fromFroName).kind;
        Class<building> fromMakerKind3 = new Maker(fromFroName).kind;

註釋掉的兩行代碼,取消註釋後,你會收穫一個編譯錯誤:Type parameter '? extends building' cannot be instantiated directly或者Type parameter '?' cannot be instantiated directly,這其實很簡單,在實例化的時候,泛型類型不允許爲帶通配符的,當然,除外構造器的其他方法是可以的。

在這裏插入圖片描述
你還會收穫兩個警告:
第一個警告告訴你:Maker對象以原生類型實例化了。
第二個警告告訴你:等號兩邊的賦值,是從原生類型轉型到了Class<building>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章