千鋒逆戰班,學習了反射

學習Java的第52天,
明天的自己會感謝今天拼命的自己
今天學習了反射的類加載,類加載器,類反射機制,工廠模式,反射機制操作構造器,成員變量,成員函數,反射機制跳過泛型的限制,反射機制配置文件,靜待代理設計模式

類加載

  • 概念:在class文件加載到jvm中時,會對應創建一個Class對象;分爲三個步驟:加載、連接、初始化
  • 加載時機
    1.Class.forName(“com.mysql.jdbc.Driver”) : 將Driver類加載到jvm中的方法區
    2.初始化Fahter類的子類Son類:Father類也會加載,Son類會使用到Father類中的成員變量,Father類中成員變量就需要進行初始化,就需要將Father加載到內存,子類要調用父類的構造方法。

類加載器

  • 概念
    將class文件加載進內存,並生成對應的Class對象
  • 分類
    • 根類加載器
      • 加載java中的核心類,主要加載F:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar中的類
    • 擴展類加載器
      • 加載java中的擴展類,主要加載F:\Program Files\Java\jdk1.8.0_202\jre\lib\ext所有jar包中的類
    • 系統類加載器
      • 加載開發人員編寫的自定義類、以及一些第三方的jar包中類

類的反射機制

  • 概念
    通過類的Class對象,動態去調用類中的屬性和方法
  • 獲取Class對象方式
    • 全類名=包名.類名
      • Class.forName(“全類名”)
    • 編譯期
      • 類名.class
    • 運行時
      • 對象名.getClass()

反射結合工廠模式

  • 工廠模式的最大作用是創建類的對象,從而讓模塊和模塊之間的耦合度也叫關聯性降低,這樣代碼的拓展方便,
  • 反射在裏面就是按照配置文件的內的類全限定名來創建哪一個類的對象

反射操作構造器

 //獲取User類對應的Class對象
        Class<?> acl = Class.forName("com.qf.bean.User");
        //通過獲取的Class對象獲取無參構造方法
        Constructor<?> cl = acl.getConstructor();
        //通過無參構造方法創建對象
        Object o1 = cl.newInstance();
        System.out.println(o1);

        System.out.println("-------------------------------------");
        //獲取User類對應的有參構造方法對象
        Constructor<?> constructor = acl.getConstructor(Integer.class, String.class, String.class);
        //使用有參創建User對象
        Object o2 = constructor.newInstance(2, "ww", "888");
        System.out.println(o2);

        //獲取私有構造方法
        Constructor<?> declaredConstructor = acl.getDeclaredConstructor(String.class, String.class);
        //暴力反射
        declaredConstructor.setAccessible(true);
        Object o3 = declaredConstructor.newInstance("大大大", "555");
        System.out.println(o3);

反射操作成員變量

  //獲取User類的Class對象
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        //操作public修飾的成員變量
        Field idField = userClass.getField("id");
        //設置該成員變量值
        //obj:需要設置的對象
        //value:需要設置的值
        //給user對象的id屬性設置值爲2
        idField.set(user,2);
        System.out.println(user);
        //獲取該成員變量值
        Object idValues = idField.get(user);
        System.out.println(idValues);

        //操作非public修飾的成員變量
        Field username = userClass.getDeclaredField("username");
        //暴力反射
        username.setAccessible(true);
        username.set(user,"花花");

        System.out.println(user);

        Object o = username.get(user);
        System.out.println(o);

反射操作成員方法

//獲取User的Class對象
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        //獲取public成員方法
        Method setId = userClass.getMethod("setId", Integer.class);
        //使用方法對象
        //obj:哪個對象在執行該方法
        //args:方法執行時所需的參數值
        Object invoke = setId.invoke(user, 3);
        System.out.println(user);

        //獲取非public成員方法
        Method setUsername = userClass.getDeclaredMethod("show");
        //暴力反射
        setUsername.setAccessible(true);
        Object value = setUsername.invoke(user);
        System.out.println(value);
        System.out.println(user);
    

反射越過泛型檢查

 List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list);

        //泛型只在編譯期有效!!!
        //反射越過泛型檢查
        //反射可以在程序運行時,動態地調用List中的add方法去添加元素

        Class<? extends List> aClass = list.getClass();
        Method add = aClass.getMethod("add", Object.class);
        Object hello = add.invoke(list, "hello");
        System.out.println(list);

反射通用方法案例

  • 需求

      給指定對象的指定字段設置指定值
    
Class<?> aClass = obj.getClass();
        Object o1 = aClass.newInstance();
        //方法名規範:如果只有一個單詞,所有的字母全都小寫。如果有多個單詞,從第二個單詞開始,首字母大寫!!!
        //變量名規範: 如果只有一個單詞,所有的字母全都小寫。如果有多個單詞,從第二個單詞開始,首字母大寫!!!
        //username setUsername
        //根據屬性名稱獲取對應的set方法名稱
        //String methodName = "set" + "U" + "sername";
        String str = "set" + s.substring(0, 1).toUpperCase() + s.substring(1);
        Field declaredField = aClass.getDeclaredField(s);
        //獲取字段(屬性)的數據類型
        Class<?> type = declaredField.getType();
        //獲取set方法對象
        Method method = aClass.getMethod(str, type);
        //執行set方法
        method.invoke(obj,o);

反射結合配置文件

  • 需求

  • 編寫bean.properties,配置對象的唯一標識及對象的全類名,根據這段配置創建一個對象

bean01=com.qf.bean.User
bean02=com.qf.bean.Banana
 //需求:編寫bean.properties,配置對象的唯一標識及對象的全類名,根據這段配置創建一個對象
        Properties properties = new Properties();
        //將bean.properties中的數據存儲到resourceAsStream中
        InputStream resourceAsStream = Demo11.class.getResourceAsStream("/bean.properties");
        //將bean.properties中的數據綁定到了Properties中!
        properties.load(resourceAsStream);
        //根據全類名,創建Class對象
        Class<?> bean01 = Class.forName(properties.getProperty("bean01"));
        //根據Class對象創建對象
        Object o = bean01.newInstance();
        System.out.println(o);


        Class<?> bean02 = Class.forName(properties.getProperty("bean02"));
        Object o1 = bean02.newInstance();
        System.out.println(o1);

靜態代理設計模式

  • 概念
    • 增強被代理類的功能
  • 步驟
    • 自定義類實現和被代理類相同的接口
    • 在代理類中聲明被代理類的對象
    • 在代理類的方法中使用被代理類調用方法
  • 代碼實現
//1,自定義一個代理類(增強類)實現和被代理類(被增強類)相同的接口
public class UserDaoImplProxy implements UserDao{

    //2,在代理類中聲明被代理類的引用
    private UserDao userDao ;
    public UserDaoImplProxy(){
        userDao = new UserDaoImpl();
    }
    @Override
    public void addUser() {
        //3,在代理類的方法中使用被代理類調用方法
        System.out.println("權限校驗");
        userDao.addUser();
        System.out.println("日誌記錄");
    }

    @Override
    public void deleteUser() {
        userDao.deleteUser();
    }
    @Override
    public void updateUser() {
        userDao.updateUser();
    }
    @Override
    public void selectUser() {
        userDao.selectUser();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章