java基礎語法(三十九)—反射機制(二)

順毛黑起發表於2020-12-10

反射的概述

java在計算機中獎勵的三個階段如下圖所示:
在這裡插入圖片描述
框架:半成品軟體。可以在框架的基礎上進行軟體開發,簡化編碼。
反射:將類的各個組成部分封裝為其他物件,這就是反射機制。
好處:

  1. 可以在程式執行過程中操作這些物件
  2. 可以解耦,提高程式的可擴充套件性
    獲取Class物件的方式:
  3. Class.forName(“全類名”):將位元組碼檔案載入記憶體,返回Class物件
  4. 類名.class:通過類名的屬性class獲取
  5. 物件.getClass():getClass()方法在Object類中定義
    結論:
    同一個位元組碼檔案(*.class)在一次程式執行過程當中,只會被載入一次,無論是通過哪一種方式獲取的Class物件都是同一個

Constructor:構造方法
建立物件:
T newInstance(Object… initargs)
如果使用空引數的構造方法建立物件,操作可以簡化:Class物件的newInstance方法
Method:方法物件
執行方法:
Object invoke(Object obj,Object… args) 傳遞真實的物件以及方法的實際引數列表
獲取方法名稱:
String getName:獲取方法名

獲取Class物件的三種方式

  • 獲取Class物件的方式:
    1. Class.forName(“全類名”):將位元組碼檔案載入記憶體,返回Class物件
      多用於配置檔案,將類名定義在配置檔案中。讀取檔案,載入類
    1. 類名.class:通過類名的屬性class獲取
      多用於引數的傳遞
    1. 物件.getClass():getClass()方法在Object類中定義
      多用於物件的獲取位元組碼的方式
public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {
        //1. Class.forName(“全類名”)
        Class cls1=Class.forName("com.company.reflect.domain.Person");
        System.out.println(cls1);//class com.company.reflect.domain.Person

        //2. 類名.class
        Class cls2= Person.class;
        System.out.println(cls2);

        //3. 物件.getClass()
        Person p=new Person();
        Class cls3=p.getClass();
        System.out.println(cls3);

        //==比較三個物件
        System.out.println(cls1==cls2);//true
        System.out.println(cls1==cls3);//true
    }
}

Class物件功能概述

  • Class物件功能
  • 獲取功能:
  1. 獲取成員變數們
  •  Field[] getFields()  獲取所有public修飾的成員變數
    
  •  Field getField(String name)獲取指定名稱的public修飾的成員變數
    
  •  Field[] getDeclaredFields()
    
  •  Field getDeclaredField(String name)
    
  1. 獲取構造方法們
  •  Constructor<?>[] getConstructors()
    
  •  Constructor<T> getConstructor(類<?>... parameterTypes)
    
  •  Constructor<T>getDeclaredConstructor(類<?>... parameterTypes)
    
  •  Constructor<?>[] getDeclaredConstructors()
    
  1. 獲取成員方法們
  •  Method[] getMethods()
    
  •  Method getMethod(String name,類<?>... parameterTypes)
    
  •  Method[] getDeclaredMethods()
    
  •  Method getDeclaredMethod(String name,類<?>... parameterTypes)
    
  1. 獲取類名
  •  String getName()
    
public class ReflectDemo2 {
    public static void main(String[] args) throws  Exception {
        //0 獲取Person的Class物件
        Class personClass=Person.class;

        /*
            獲取成員變數們
               Field[] getFields()
               Field getField(String name)

               Field[] getDeclaredFields()
               Field getDeclaredField(String name)
         */
        //1.Field[] getFields()  獲取所有public修飾的成員變數
        Field[] fields=personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);//public java.lang.String com.company.reflect.domain.Person.a
        }
        System.out.println("----------------------------");
        //2.Field getField(String name)
        Field a=personClass.getField("a");
        //獲取成員變數a的值
        Person p=new Person();
        Object value=a.get(p);
        System.out.println(value);//null
        //設定a的值
        a.set(p,"張三");
        System.out.println(p);
        System.out.println("------------------------");
        //3. Field[] getDeclaredFields():獲取所有的成員變數,不考慮修飾符
        Field[] declaredFields=personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        //4.  Field getDeclaredField(String name)
        Field d=personClass.getDeclaredField("d");
        //忽略訪問許可權修飾符的安全檢查
        d.setAccessible(true);//暴力反射
        Object value2=d.get(p);
        System.out.println(value2);
    }
}
public class ReflectDemo3 {
    public static void main(String[] args) throws  Exception {
        //0 獲取Person的Class物件
        Class personClass=Person.class;

        /*
            獲取構造方法們
                Constructor<?>[] getConstructors()
                Constructor<T> getConstructor(類<?>... parameterTypes)

                Constructor<T>getDeclaredConstructor(類<?>... parameterTypes)
                Constructor<?>[] getDeclaredConstructors()
         */
         // Constructor<T> getConstructor(類<?>... parameterTypes)
        Constructor constructor=personClass.getConstructor(String.class,int.class);
        System.out.println(constructor);//public com.company.reflect.domain.Person(java.lang.String,int)
        //建立物件
        Object person=constructor.newInstance("張三",23);
        System.out.println(person);

        System.out.println("--------------------------------------------------");
        Constructor constructor1=personClass.getConstructor( );
        System.out.println(constructor1);//public com.company.reflect.domain.Person(java.lang.String,int)
        //建立物件
        Object person1=constructor1.newInstance( );
        System.out.println(person1);

        Object o=personClass.newInstance();
        System.out.println(o);


    }
}

public class ReflectDemo4 {
    public static void main(String[] args) throws  Exception {
        //0 獲取Person的Class物件
        Class personClass=Person.class;

        /*
            獲取成員方法們
                Method[] getMethods()
                Method getMethod(String name,類<?>... parameterTypes)

               Method[] getDeclaredMethods()
               Method getDeclaredMethod(String name,類<?>... parameterTypes)
         */
         //獲取指定名稱的方法
        Method eat_method=personClass.getMethod("eat");
        Person p=new Person();
        //執行方法
        eat_method.invoke(p);

        Method eat_method2 =personClass.getMethod("eat",String.class);
        //執行方法
        eat_method2.invoke(p,"飯");

        System.out.println("--------------------------------");
        //獲取所有public修飾的方法
        Method[] methods=personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            //method.setAccessible(true);
            String name=method.getName();
            System.out.println(name);

        }

        //獲取類名
        String className=personClass.getName();
        System.out.println(className);
    }
}

反射的案例

要求:
可以建立任意類的物件,可以執行任意方法

        前提:不能改變該類的任何程式碼,可以建立任意類的物件,可以執行任意方法

先建立兩個類
Person類:

package com.company.reflect.domain;

public class Person {
    private String name;
    private int age;

    public String a;
    protected String b;
    String c;
    private String d;
    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                '}';
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat(){
        System.out.println("eat...");
    }

    public void eat(String food){
        System.out.println("eat..."+food);
    }


}

Student類

package com.company.reflect.domain;

public class Student {
    public void sleep(){
        System.out.println("sleep...");
    }
}

import com.company.reflect.domain.Person;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 框架類
 */
public class ReflectTest {
    public static void main(String[] args) throws  Exception {

        //1.載入配置檔案
        //1.1建立Properties物件
        Properties pro=new Properties();
        //1.2 載入配置檔案,轉換為一個集合
        //1.2.1 獲取class目錄下的配置檔案
        ClassLoader classLoader=ReflectTest.class.getClassLoader();//獲取ReflectTest類物件所在的類載入器,通過該類載入器獲得配置檔案所在的路徑
        InputStream is=classLoader.getResourceAsStream("pro.properties");//該方法獲得資源所對應的位元組流
        pro.load(is);

        //2.獲取配置檔案中定義的資料
        String className=pro.getProperty("className");
        String methodName=pro.getProperty("methodName");

        //3.載入該類進記憶體
        Class cls=Class.forName(className);
        //4.建立物件
        Object obj=cls.newInstance();
        //5.獲取方法物件
        Method method=cls.getMethod(methodName);
        //6.執行方法
        method.invoke(obj);
    }
}

配置檔案在根目錄下生成(pro.properties 配置如下)

className=com.company.reflect.domain.Person
methodName=eat

相關文章