成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊Java知識點之反射

開發 后端
對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性。

[[376644]]

前言

今天說Java模塊內容:反射。

反射介紹

正常情況下,我們知曉我們要操作的類和對象是什么,可以直接操作這些對象中的變量和方法,比如一個User類:

  1. User user=new User(); 
  2. user.setName("Bob"); 

但是有的場景,我們無法正常去操作:

  • 只知道類路徑,無法直接實例化的對象。
  • 無法直接操作某個對象的變量和方法,比如私有方法,私有變量。
  • 需要hook系統邏輯,比如修改某個實例的參數。

等等情況。

所以我們就需要一種機制能讓我們去操作任意的類和對象。

這種機制,就是反射。簡單的說,反射就是:

對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性。

常用API舉例

先設定一個User類:

  1. package com.example.testapplication.reflection; 
  2. public class User { 
  3.     private int age; 
  4.     public String name
  5.  
  6.     public User() { 
  7.         System.out.println("調用了User()"); 
  8.     } 
  9.  
  10.     private User(int age, String name) { 
  11.         this.name = name
  12.         this.age = age; 
  13.         System.out.println("調用了User(age,name)"+"__age:"+age+"__name:"+name); 
  14.     } 
  15.  
  16.     public User(String name) { 
  17.         this.name = name
  18.         System.out.println("調用了User(name)"+"__name:"+name); 
  19.     } 
  20.  
  21.     private String getName() { 
  22.         System.out.println("調用了getName()"); 
  23.         return this.name
  24.     } 
  25.  
  26.     private String setName(String name) { 
  27.      this.name = name
  28.         System.out.println("調用了setName(name)__"+name); 
  29.         return this.name
  30.     } 
  31.  
  32.     public int getAge() { 
  33.         System.out.println("調用了getAge()"); 
  34.         return this.age; 
  35.     }     

獲取Class對象

  • 主要有三種方法獲取Class對象:
  • 根據類路徑獲取類對象
  • 直接獲取

實例對象的getclass方法

  1. //1、根據類路徑獲取類對象 
  2. try { 
  3.     Class clz = Class.forName("com.example.testapplication.reflection.User"); 
  4. } catch (ClassNotFoundException e) { 
  5.     e.printStackTrace(); 
  6.  
  7. //2、直接獲取 
  8. Class clz = User.class; 
  9.  
  10. //3、對象的getclass方法 
  11. Class clz = new User().getClass(); 

獲取類的構造方法

1、獲取類所有構造方法

  1. Class clz = User.class; 
  2. //獲取所有構造函數(不包括私有構造方法) 
  3. Constructor[] constructors1 = clz.getConstructors(); 
  4. //獲取所有構造函數(包括私有構造方法) 
  5. Constructor[] constructors2 = clz.getDeclaredConstructors(); 

2、獲取類的單個構造方法

  1. try { 
  2.        //獲取無參構造函數 
  3.        Constructor constructor1 = clz.getConstructor(); 
  4.  
  5.        //獲取參數為String的構造函數 
  6.        Constructor constructor2 =clz.getConstructor(String.class); 
  7.  
  8.        //獲取參數為int,String的構造函數 
  9.        Class[] params = {int.class,String.class}; 
  10.        Constructor constructor3 =clz.getDeclaredConstructor(params); 
  11.    } catch (NoSuchMethodException e) { 
  12.        e.printStackTrace(); 
  13.    } 

需要注意的是,User(int age, String name)為私有構造方法,所以需要使用getDeclaredConstructor獲取。

調用類的構造方法生成實例對象

1、調用Class對象的newInstance方法

這個方法只能調用無參構造函數,也就是Class對象的newInstance方法不能傳入參數。

  1. Object user = clz.newInstance(); 

2、調用Constructor對象的newInstance方法

  1. Class[] params = {int.class,String.class}; 
  2. Constructor constructor3 =clz.getDeclaredConstructor(params); 
  3. constructor3.setAccessible(true); 
  4. constructor3.newInstance(22,"Bob"); 

這里要注意下,雖然getDeclaredConstructor能獲取私有構造方法,但是如果要調用這個私有方法,需要設置setAccessible(true)方法,否則會報錯:

  1. can not access a member of class com.example.testapplication.reflection.User with modifiers "private" 

獲取類的屬性(包括私有屬性)

  1. Class clz = User.class; 
  2. Field field1 = clz.getField("name"); 
  3. Field field2 = clz.getDeclaredField("age"); 

同樣的,getField獲取public類變量,getDeclaredField可以獲取所有變量(包括私有變量屬性)。

所以一般直接用getDeclaredField即可。

修改實例的屬性

接上例,獲取類的屬性后,可以去修改類實例的對應屬性,比如我們有個user的實例對象,我們來修改它的name和age。

  1. //修改namenamepublic屬性 
  2. Class clz = User.class; 
  3. Field field1 = clz.getField("name"); 
  4. field1.set(user,"xixi"); 
  5.  
  6. //修改age,age為private屬性 
  7. Class clz = User.class; 
  8. Field field2 = clz.getDeclaredField("age"); 
  9. field2.setAccessible(true); 
  10. field2.set(user,123); 

獲取類的方法(包括私有方法)

  1.   //獲取getName方法 
  2.    Method method1 = clz.getDeclaredMethod("getName"); 
  3. //獲取setName方法,帶參數 
  4.    Method method2 = clz.getDeclaredMethod("setName", String.class); 
  5.    //獲取getage方法 
  6.    Method method3 = clz.getMethod("getAge"); 

調用實例的方法

  1. method1.setAccessible(true); 
  2. Object name = method1.invoke(user); 
  3.  
  4.  
  5. method2.setAccessible(true); 
  6. method2.invoke(user"xixi"); 
  7.  
  8. Object age = method3.invoke(user); 

反射優缺點

雖然反射很好用,增加了程序的靈活性,但是也有他的缺點:

  • 性能問題。由于用到動態類型(運行時才檢查類型),所以反射的效率比較低。但是對程序的影響比較小,除非對性能要求比較高。所以需要在兩者之間平衡。
  • 不夠安全。由于可以執行一些私有的屬性和方法,所以可能會帶來安全問題。
  • 不易讀寫。當然這一點也有解決方案,比如jOOR庫,但是不適用于Android定義為final的字段。

Android中的應用

插件化(Hook)

Hook 技術又叫做鉤子函數,在系統沒有調用該函數之前,鉤子程序就先捕獲該消息,鉤子函數先得到控制權,這時鉤子函數既可以加工處理(改變)該函數的執行行為,還可以強制結束消息的傳遞。

在插件化中,我們需要找到可以hook的點,然后進行一些插件的工作,比如替換Activity,替換mH等等。這其中就用到大量反射的知識,這里以替換mH為例:

  1. // 獲取到當前的ActivityThread對象 
  2. Class<?> activityThreadClass = Class.forName("android.app.ActivityThread"); 
  3. Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread"); 
  4. currentActivityThreadField.setAccessible(true); 
  5. Object currentActivityThread = currentActivityThreadField.get(null); 
  6.  
  7. //獲取這個對象的mH 
  8. Field mHField = activityThreadClass.getDeclaredField("mH"); 
  9. mHField.setAccessible(true); 
  10. Handler mH = (Handler) mHField.get(currentActivityThread); 
  11.  
  12.  
  13. //替換mh為我們自己的HandlerCallback 
  14. Field mCallBackField = Handler.class.getDeclaredField("mCallback"); 
  15. mCallBackField.setAccessible(true); 
  16. mCallBackField.set(mH, new MyActivityThreadHandlerCallback(mH)); 

動態代理

動態代理的特點是不需要提前創建代理對象,而是利用反射機制在運行時創建代理類,從而動態實現代理功能。

  1. public class InvocationTest implements InvocationHandler { 
  2.     // 代理對象(代理接口) 
  3.     private Object subject; 
  4.  
  5.     public InvocationTest(Object subject) { 
  6.         this.subject = subject; 
  7.     } 
  8.     @Override 
  9.     public Object invoke(Object object, Method method, Object[] args) 
  10.             throws Throwable { 
  11.         //代理真實對象之前 
  12.         Object obj = method.invoke(subject, args); 
  13.         //代理真實對象之后 
  14.         return obj; 
  15.     } 

三方庫(注解)

我們可以發現很多庫都會用到注解,而獲取注解的過程也會有反射的過程,比如獲取Activity中所有變量的注解:

  1. public void getAnnotation(Activity activity){ 
  2.     Class clazz = activity.getClass(); 
  3.     //獲得activity中的所有變量 
  4.     Field[] fields = clazz.getDeclaredFields(); 
  5.     for (Field field : fields) { 
  6.         field.setAccessible(true); 
  7.         //獲取變量上加的注解 
  8.         MyAnnotation test = field.getAnnotation(MyAnnotation.class); 
  9.         //... 
  10.     } 

這種通過反射處理注解的方式稱作運行時注解,也就是程序運行狀態的時候才會去處理注解。但是上文說過了,反射會在一定程度上影響到程序的性能,所以還有一種處理注解的方式:編譯時注解。

所用到的注解處理工具是APT。

APT是一種注解處理器,可以在編譯時進行掃描和處理注解,然后生成java代碼文件,這種方法對比反射就能比較小的影響到程序的運行性能。

這里就不說APT的使用了,下次會專門有章節提到~

Android體系架構

Android體系架構:https://github.com/JiMuzz/Android-Architecture

參考

https://www.jianshu.com/p/3382cc765b39

https://segmentfault.com/a/1190000015860183

本文轉載自微信公眾號「碼上積木」,可以通過以下二維碼關注。轉載本文請聯系碼上積木公眾號。

 

責任編輯:武曉燕 來源: 碼上積木
相關推薦

2021-04-07 07:48:00

測試開發Java反射Spring

2020-10-26 10:40:31

Axios前端攔截器

2018-01-25 12:50:33

數據庫OracleROWNUM

2025-05-07 08:55:00

2010-08-17 14:56:00

HCNE認證

2011-04-15 12:25:21

BGP路由

2016-05-30 17:31:34

Spring框架

2022-12-13 08:23:25

CSS前端漸變

2021-12-30 08:17:27

Springboot數據訪問DataSourceB

2010-12-24 10:23:50

程序員

2010-12-30 10:18:54

程序員

2011-01-05 14:53:53

程序員

2011-01-28 10:53:18

程序員

2010-12-23 11:18:16

程序員

2010-12-27 10:08:22

程序員

2011-01-07 10:54:39

程序員

2011-01-11 11:37:03

程序員

2011-01-14 11:03:32

程序員

2011-01-18 11:41:26

程序員

2021-04-13 08:25:12

測試開發Java注解Spring
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一级黄色片免费观看 | 欧美一级做性受免费大片免费 | 久久久国产精品一区 | 天天插天天操 | 国产精品久久久久一区二区三区 | 午夜资源 | 欧美黄色网络 | 欧美a在线| av在线二区 | 亚洲自拍偷拍免费视频 | 国产在线1 | 久久久久久亚洲精品 | 欧美无乱码久久久免费午夜一区 | 精品久久久久久亚洲精品 | 日韩毛片中文字幕 | 免费一区二区 | 99精品视频在线 | 国产一区二区日韩 | 久久久久网站 | 成人一区二区三区在线观看 | 91av在线免费 | 国产免费视频 | 久草网址| 国产精品日韩在线 | 激情在线视频 | 精品久久久久久久久久久院品网 | 在线播放一区 | 亚洲视频一区二区三区 | 色欧美片视频在线观看 | 精品在线免费观看视频 | 色婷婷综合网站 | www中文字幕 | 久久久性色精品国产免费观看 | 91麻豆精品国产91久久久久久 | 国产精品久久久久影院色老大 | 久久久噜噜噜久久中文字幕色伊伊 | 亚洲欧美日韩网站 | 中文字幕一区二区三区四区 | 91av国产在线视频 | 野狼在线社区2017入口 | 国产精品久久久久久久久久免费看 |