通過反射獲取對象的構造器


在學習這個之前,先復習下對象構造器的作用。

一、構造器:

構造方法的名字必須和所在類的名字一致,沒有返回值,但不能聲明void,訪問權限可以為任意,但是一般情況下使用public方法權限,構造方法中的參數可以根據需要自行定義,參數的不同的構造方法構成重載;

例如:

public class Person {
    private String name;
    private String age;
    //getter setter ..
    public static void main(String[] args) {
        Person person = new Person();
    }
}

 這個Person對象,我們在通過new的時候,默認調用了對象的無參構造方法,通過無參構造方法對這個類進行初始化,當我們沒有給出構造方法的時候,java會默認提供一個無參構造器。

當我給類一個構造器的時候,會默認覆蓋類中的無參構造

public class Person {
    private String name;
    private Integer age;
    Person(String name,Integer age){
        this.age = age;
        this.name = name;
    }
    //getter setter ..
    public static void main(String[] args) {
        Person person = new Person("張三",20);
    }
}

 

在這個類中,我們就調用了我們創建的構造器去初始化對象

構造方法中的參數可以根據需要自行定義,參數的不同的構造方法構成重載

例:

public class Fu {
    Fu(){}//無參公有的構造方法
    Fu(int i){} //參數為Int的公有構造方法
}
public class Zi extends Fu{
    Zi(){} //無參的公有構造方法
    Zi(int i){} //參數類型為int的公有構造方法
    Zi(int i,double d){} //參數類型為int和double的公有構造方法
}

 java中構造方法的使用有兩個地方,一個是跟在關鍵字new后面,類名加上一個小括號(),小括號內根據實際加上實參,

另外一個是跟在關鍵字super或this后加上一個小括號(),小括號內根據實際添加實參,下面進行舉例。

調用本類的構造方法:

public class Zi extends Fu {
    Zi() {
        this(2);//調用參數為int類型的本類的構造方法
    }
}

 

調用父類的構造方法:

public class Zi extends Fu {
    Zi() {
        super(2);//調用參數為int類型的父類的構造方法
    }
}

 

注意:

public class Zi extends Fu {
    /**
     * 注意:例子中中this或super調用構造方法只能出現在構造方法中,
     * 而且必須出現在第一行,所以一個構造方法中第一行只能為this或super
     * 調用構造方法,兩者不能同時調用構造方法出現,而且注意this或super
     * 調用構造方法時,要留構造方法出口,意思就是最后調用的構造方法中沒
     * 有再調用別的構造方法!(下面並不能一起參數相同的構造器,演示需求)
     */
    Zi() {
        this(2);//調用參數為int類型的本類的構造方法
    }
    Zi() {
        super(2);//調用參數為int類型的父類的構造方法
    }
}
 
構造方法的作用 
  • 為了初始化成員屬性,而不是初始化對象,初始化對象是通過new關鍵字實現的
  • 通過new調用構造方法初始化對象,編譯時根據參數簽名來檢查構造函數,稱為靜態聯編和編譯多態(參數簽名:參數的類型,參數個數和參數順序)
  • 創建子類對象會調用父類構造方法但不會創建父類對象,只是調用父類構造方法初始化父類成員屬性

我總是要把構造器和方法混淆,后來發現,方法實際上是需要用於執行java代碼的,而構造器,構造器是一個類的實例!

為什么呢?

類的實例,我們需要用類來創建對象,進而訪問其屬性,因為實例是需要被用來調用的,但是調用的話,我們不得不去考慮一個問題,就是對象,最終是被存儲在內存里面的,而存儲的時候,

我們的內存不得不需要給他再另外開辟新的內存空間,那么,java是如何給這種我們所需要的類來開辟內存空間的呢?這就涉及到了java的內存機制,就是說,我們必須要給這個類制作一個構造器,

而且這個構造器的名稱必須和這個類的名稱是一致的,這樣,我們的java編譯器才能識別這個類,進而給這個類在內存中開辟內存空間,也就是我們所說的,我們手動,人為的給他進行“初始化”,事例如下:

public class Fu {
    Fu(){
        System.out.println("Construct");
    }//無參公有的構造方法
    Fu(int i){} //參數為Int的公有構造方法
}

 

  這樣,當我們在對Fu類進行調用的時候,我們的java編譯器就會事先對他進行“自動”地初始化,開辟內存空間

  那么現在問題又來了,舉個例子,我們的Fu()方法需要帶有一個參數,形參,但是整個代碼中,需要不僅僅是帶有形參的Fu();還需要不帶形參的Fu(),在我們的構造器對類進行構造的時候,

需要將功能類似的,但形參不同的方法同時打包在該類下,以便在我們調用某個方法的時候,直接重載構造器中的該方法,可以說,這種構造形式,滿足了我們對功能類似,形參不同的方法,

調用的時候,進行重載,而滿足了編譯器自動初始化,人不需要手動初始化的需求。

  而且有個,問題,本來兩個方法,功能上是類似的,一棵樹和一株樹苗,你非得要給他們起不同的名字,多別扭,好在有了構造器,能夠是功能相似的方法起相同的名字,

不同的參數,而能夠在被調用的時候得以重載,多么牛逼的構造器啊。

 

二、通過反射獲取公共的構造器,並使用構造器創建對象

創建對象:

public class Animal {
    private  String name;
    private String sex;
    private Integer age;
    //無參構造器
    Animal(){}
    //有參構造
    Animal(String name, String sex, Integer age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}

 

/**
     * 通過獲取類的構造器來實例化對象
     */
    public static void main(String[] args) throws Exception {
        Class<?> animal = Class.forName("constructure.Animal");
        Constructor[] constructors = animal.getDeclaredConstructors();
        /**
         * 輸出:
         * constructure.Animal  0
         * ----------------
         * constructure.Animal  3
         * class java.lang.String
         * class java.lang.String
         * class java.lang.Integer
         * ----------------
         */
        for (Constructor<?> constructor : constructors){
            //獲取類中的構造器名稱與構造器個數
            System.out.println(constructor.getName()+"  "+constructor.getParameterCount());
            //獲取構造器的參數類型
            Class<?>[] paramType = constructor.getParameterTypes();
            for (Class<?> param : paramType){
                System.out.println(param);
            }
            System.out.println("----------------");
        }
        //通過反射取得構造器並實例化對象
        //參數個數代表想要獲取的那個構造器
        Constructor<?> constructor = animal.getDeclaredConstructor();
        //調用了無構造器!
        //Animal{name='null', sex='null', age=null}
        Object animalInstance = constructor.newInstance();
        System.out.println(animalInstance);
        //調用有參構造實例化對象,先獲取有參構造器
        Constructor<?> constructor1 = animal.getDeclaredConstructor(String.class,String.class,Integer.class);
        //Animal{name='小豬', sex='公', age=10}
        Object object = constructor1.newInstance("小豬","公",10);
        System.out.println(object);
    }

 

想獲取什么構造器就根據需要的參數類型傳入getDeclaredConstructor

注意:getDeclaredConstructor 與getConstructor的區別

getDeclaredConstructor 代表獲取該class對象下所有的構造器,而getConstructor只能獲取被public聲明的構造器,有時候idea會提示多余代碼,代碼潔癖可能就將public去掉了,這樣使用getConstructor就無法獲取Construct

例如:

    //無參構造器
    public Animal(){
        System.out.println("調用了無構造器!");
    }
    Animal(){
        System.out.println("調用了無構造器!");
    }

 

這兩個無參構造器,沒有被public修飾的就無法通過getConstructor方法獲取他的構造器


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM