1. 程式人生 > 實用技巧 >java---類載入器和反射

java---類載入器和反射

類的載入

當程式要使用某個類時,如果該類還未被載入到記憶體中,則系統會通過載入,連線,初始化三步來實現對這個類進行初始化。

步驟:

1. 建立類的例項

2. 類的靜態變數,或者為靜態變數賦值

3. 類的靜態方法

4. 使用反射方式來強制建立某個類或介面對應的java.lang.Class物件

5. 初始化某個類的子類

6. 直接使用java.exe命令來執行某個主類

負責將.class檔案載入到記憶體中,併為之生成對應的Class物件。

獲取Class物件的三種方式

方式一: 通過Object類中的getObject()方法  

  Person p = new Person();

  Class c = p.getClass();

//方式二: 通過 類名.class 獲取到位元組碼檔案物件(任意資料型別都具備一個class靜態屬性,看上去要比第一種方式簡單)。
Class c2 = Person.class;
//方式三: 通過Class類中的方法(將類名作為字串傳遞給Class類中的靜態方法forName即可)。

  Class c3 = Class.forName("Person");

注意:第三種和前兩種的區別

前兩種你必須明確Person型別.

後面是指定這種型別的字串就行.這種擴充套件更強.我不需要知道你的類.我只提供字串,按照配置檔案載入就可以了

通過反射獲取構造方法並使用

/*
 * 獲取.class位元組碼檔案物件的方式
 *         1:通過Object類中的getObject()方法
 *         2: 通過 類名.class 獲取到位元組碼檔案物件 
*         3: 反射中的方法,
 *             public static Class<?> forName(String className) throws ClassNotFoundException
 *             返回與帶有給定字串名的類或介面相關聯的 Class 物件 
 
*/ public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException { // 1: 通過Object類中的getObject()方法 // Person p1 = new Person(); // Class c1 = p1.getClass(); // System.out.println("c1 = "+ c1); // 2: 通過 類名.class 獲取到位元組碼檔案物件 // Class c2 = Person.class;
// System.out.println("c2 = "+ c2); // 3: 反射中的方法 Class c3 = Class.forName("cn.oracle_01_Reflect.Person");// 包名.類名 System.out.println("c3 = " + c3); } } // Person類 package cn.oracle_01_Reflect; public class Person { //成員變數 public String name; public int age; private String address; //構造方法 public Person() { System.out.println("空引數構造方法"); } public Person(String name) { this.name = name; System.out.println("帶有String的構造方法"); } //私有的構造方法 private Person(String name, int age){ this.name = name; this.age = age; System.out.println("帶有String,int的構造方法"); } public Person(String name, int age, String address){ this.name = name; this.age = age; this.address = address; System.out.println("帶有String, int, String的構造方法"); } //成員方法 //沒有返回值沒有引數的方法 public void method1(){ System.out.println("沒有返回值沒有引數的方法"); } //沒有返回值,有引數的方法 public void method2(String name){ System.out.println("沒有返回值,有引數的方法 name= "+ name); } //有返回值,沒有引數 public int method3(){ System.out.println("有返回值,沒有引數的方法"); return 123; } //有返回值,有引數的方法 public String method4(String name){ System.out.println("有返回值,有引數的方法"); return "哈哈" + name; } //私有方法 private void method5(){ System.out.println("私有方法"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]"; } }

獲取構造方法的程式碼演示:

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
        //獲取Class物件
        Class c = Class.forName("cn.oracle_01_Reflect.Person");//包名.類名
        
        //獲取所有的構造方法
        //Constructor[] cons = c.getConstructors();
        Constructor[] cons = c.getDeclaredConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }
        
        System.out.println("------------------------");
        //獲取一個構造方法
        //public Person() 
        Constructor con1 = c.getConstructor(null);
        System.out.println(con1);
        
        //public Person(String name)
        Constructor con2 = c.getConstructor(String.class);
        System.out.println(con2);
        
        //private Person(String name, int age)
        Constructor con3 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(con3);
        
        //public Person(String name, int age, String address)
        Constructor con4 = c.getDeclaredConstructor(String.class, int.class, String.class);
        System.out.println(con4);
    }
}

通過反射方式,獲取構造方法,建立物件

步驟如下:

1. 獲取到Class物件

2. 獲取指定的構造方法

3. 通過構造方法類Constructor中的方法,建立物件

public T newInstance(Object... initargs)

//    程式碼演示
public class ConstructorDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        //1,獲取到Class物件
        Class c = Class.forName("cn.oracle_01_Reflect.Person");//包名.類名
        //2,獲取指定的構造方法
        //public Person()
        //Constructor con = c.getConstructor(null);
        
        //public Person(String name, int age, String address)
        Constructor con = c.getConstructor(String.class, int.class, String.class);
        
        //3,通過構造方法類中Constructor的方法,建立物件
        //Object obj = con.newInstance(null);
        Object obj = con.newInstance("小明", 22, "哈爾濱");
        
        //顯示
        System.out.println(obj);
    }
}

通過反射獲取成員變數並使用

在反射機制中,把類中的成員變數使用類Field表示。可通過Class類中提供的方法獲取成員變數:

返回一個成員變數:

public Field getField(String name) 獲取指定的 public修飾的變數

public Field getDeclaredField(String name) 獲取指定的任意變數

返回多個成員變數

public Field[] getFields() 獲取所有public 修飾的變數

public Field[] getDeclaredFields() 獲取所有的 變數 (包含私有)

獲取成員變數的程式碼演示:

public class FieldDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
        //獲取Class物件
        Class c = Class.forName("cn.oracle_01_Reflect.Person");
        
        //獲取成員變數
        //多個變數
        //Field[] fields = c.getFields();
        Field[] fields =  c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("-----------------");
        //一個變數
        //public int age;
        Field ageField = c.getField("age");
        System.out.println(ageField);
        
        //private String address
        Field addressField = c.getDeclaredField("address");
        System.out.println(addressField);
    }
}

通過反射,建立物件,獲取指定的成員變數,進行賦值與獲取值操作

獲取成員變數,步驟如下:

1. 獲取Class物件

2. 獲取構造方法

3. 通過構造方法,建立物件

4. 獲取指定的成員變數(私有成員變數,通過setAccessible(booleanflag)方法暴力訪問)

5. 通過方法,給指定物件的指定成員變數賦值或者獲取值

//    程式碼演示:
public class FieldDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
        //1,獲取Class物件
        Class c = Class.forName("cn.oracle_01_Reflect.Person");
        //2,獲取構造方法
        //public Person(String name) 
        Constructor con = c.getConstructor(String.class);
        //3,通過構造方法,建立物件
        Object obj = con.newInstance("小明");
        //4,獲取指定的成員變數
        //public String name;
        Field nameField = c.getField("name");
        //public int age;
        Field ageField = c.getField("age");
        //private String address;
        Field addressField = c.getDeclaredField("address");
        addressField.setAccessible(true); //取消 Java 語言訪問檢查
        
        //5,通過方法,給指定物件的指定成員變數賦值或者獲取值
        System.out.println("name = "+ nameField.get(obj));
        System.out.println("age = "+ ageField.get(obj));
        System.out.println("address = "+ addressField.get(obj));
        
        //賦值
        ageField.set(obj, 23);
        addressField.set(obj, "凱利廣場");
        
        System.out.println("------------------------");
        System.out.println("name = "+ nameField.get(obj));
        System.out.println("age = "+ ageField.get(obj));
        System.out.println("address = "+ addressField.get(obj));
    }
}

通過反射獲取成員方法並使用

在反射機制中,把類中的成員方法使用類Method表示。可通過Class類中提供的方法獲取成員方法:

public class MethodDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
        //獲取Class物件
        Class c = Class.forName("cn.oracle_01_Reflect.Person");
        
        //獲取多個方法
        //Method[] methods = c.getMethods();
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        
        System.out.println("-----------------------");
        //獲取一個方法:
        //public void method1()
        Method method = c.getMethod("method1", null);
        System.out.println(method);
        //public String method4(String name){
        method = c.getMethod("method4", String.class);
        System.out.println(method);
        //私有方法
        //private void method5()
        method = c.getDeclaredMethod("method5", null);
        System.out.println(method);
    }
}

通過反射,建立物件,呼叫指定的方法

獲取成員方法,步驟如下:

1. 獲取Class物件

2. 獲取構造方法

3. 通過構造方法,建立物件

4. 獲取指定的方法

5. 執行找到的方法

public class MethodDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        //1, 獲取Class物件
        Class c = Class.forName("cn.oracle_01_Reflect.Person");
        //2,獲取構造方法
        //public Person(String name, int age, String address){
        Constructor con = c.getConstructor(String.class, int.class, String.class);
        //3,通過構造方法,建立物件
        Object obj = con.newInstance("小明", 23, "哈爾濱");
        //4,獲取指定的方法
        //public void method1()  沒有返回值沒有引數的方法
        //Method m1 = c.getMethod("method1", null);
        
        //public String method4(String name)
        Method m4 = c.getMethod("method4", String.class);
        
        //5,執行找到的方法
        //m1.invoke(obj, null);
        
        Object result = m4.invoke(obj, "oracle");
        System.out.println("result = " + result);
    }
}

通過反射,建立物件,呼叫指定的private 方法

取私有成員方法,步驟如下:

1. 獲取Class物件

2. 獲取構造方法

3. 通過構造方法,建立物件

4. 獲取指定的方法

5. 開啟暴力訪問

6. 執行找到的方法

public class MethodDemo3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        //1, 獲取Class物件
        Class c = Class.forName("cn.oracle_01_Reflect.Person");
        //2,獲取構造方法
        //public Person(String name, int age, String address){
        Constructor con = c.getConstructor(String.class, int.class, String.class);
        //3,通過構造方法,建立物件
        Object obj = con.newInstance("小明", 23, "哈爾濱");
        //4,獲取指定的方法
        //private void method5(){
        Method m5 = c.getDeclaredMethod("method5", null);
        //5,開啟暴力訪問
        m5.setAccessible(true);
        //6,執行找到的方法
        m5.invoke(obj, null);
    }
}

反射練習

其實程式編譯後產生的.class檔案中是沒有泛型約束的,這種現象我們稱為泛型的擦除。那麼,我們可以通過反射技術,來完成向有泛型約束的集合中,新增任意型別的元素

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        ArrayList<Integer> list = new ArrayList<Integer>();
        //新增元素到集合
        list.add(new Integer(30));
        list.add(new Integer("12345"));
        list.add(123);
        //list.add("哈哈");//因為有泛型型別的約束
        System.out.println(list);
        
        //通過反射技術,實現新增任意型別的元素
        //1, 獲取位元組碼檔案物件
        //Class c = list.getClass();
        //Class c = ArrayList.class;
        Class c = Class.forName("java.util.ArrayList");
        
        //2, 找到add()方法
        // public boolean add(E e)
        Method addMethod = c.getMethod("add", Object.class);
        
        //3,  執行add()方法
        addMethod.invoke(list, "哈哈");// list.add("哈哈");
        System.out.println(list);
    }
}

反射配置檔案

通過反射配置檔案,執行配置檔案中指定類的對應方法

className=cn.oracle_01_Reflect.Person
methodName=method5

讀取配置檔案,呼叫指定類中的對應方法

public class ReflectTest2 {
    public static void main(String[] args)
            throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchMethodException, SecurityException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        // 通過Properties集合從檔案中讀取資料
        Properties prop = new Properties();
        // 讀取檔案中的資料到集合中
        prop.load(new FileInputStream("properties.txt"));
        // 獲取鍵所對應的值
        String className = prop.getProperty("className");
        System.out.println(className);

        // 1,獲取Person.class 位元組碼檔案物件
        Class c = Class.forName(className);
        // 2,獲取構造方法
        // public Person(String name, int age, String address)
        Constructor con = c.getConstructor(String.class, int.class, String.class);

        // 3,建立物件
        Object obj = con.newInstance("小明", 20, "中國");
        System.out.println(obj);

        // 4,獲取指定的方法
        // private void method5(){}
        String methodName = prop.getProperty("methodName");
        Method m5 = c.getDeclaredMethod(methodName, null);
        // 5,開啟暴力訪問
        m5.setAccessible(true);
        // 6,執行找到的方法
        m5.invoke(obj, null);
    }
}