<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【168期】面試官:框架中處處可見(jiàn)反射的運(yùn)用,你對(duì)它了解多少?

          共 26978字,需瀏覽 54分鐘

           ·

          2021-04-01 00:11

          程序員的成長(zhǎng)之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享 
          關(guān)注


          閱讀本文大概需要 7 分鐘。

          來(lái)自:https://zhuanlan.zhihu.com/p/21423208

          什么是反射?

          反射是一種能夠在程序運(yùn)行時(shí)動(dòng)態(tài)訪(fǎng)問(wèn)、修改某個(gè)類(lèi)中任意屬性(狀態(tài))和方法(行為)的機(jī)制(包括private實(shí)例和方法),java反射機(jī)制提供了以下幾個(gè)功能:
          • 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類(lèi);

          • 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類(lèi)的對(duì)象;

          • 在運(yùn)行時(shí)判斷任意一個(gè)類(lèi)所具有的成員變量和方法;

          • 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法。

          反射涉及到四個(gè)核心類(lèi):
          • java.lang.Class.java:類(lèi)對(duì)象;

          • java.lang.reflect.Constructor.java:類(lèi)的構(gòu)造器對(duì)象;

          • java.lang.reflect.Method.java:類(lèi)的方法對(duì)象;

          • java.lang.reflect.Field.java:類(lèi)的屬性對(duì)象;

          反射有什么用?

          • 操作因訪(fǎng)問(wèn)權(quán)限限制的屬性和方法;

          • 實(shí)現(xiàn)自定義注解;

          • 動(dòng)態(tài)加載第三方j(luò)ar包,解決android開(kāi)發(fā)中方法數(shù)不能超過(guò)65536個(gè)的問(wèn)題;

          • 按需加載類(lèi),節(jié)省編譯和初始化APK的時(shí)間;

          反射工作原理

          當(dāng)我們編寫(xiě)完一個(gè)Java項(xiàng)目之后,每個(gè)java文件都會(huì)被編譯成一個(gè).class文件,這些Class對(duì)象承載了這個(gè)類(lèi)的所有信息,包括父類(lèi)、接口、構(gòu)造函數(shù)、方法、屬性等,這些class文件在程序運(yùn)行時(shí)會(huì)被ClassLoader加載到虛擬機(jī)中。
          當(dāng)一個(gè)類(lèi)被加載以后,Java虛擬機(jī)就會(huì)在內(nèi)存中自動(dòng)產(chǎn)生一個(gè)Class對(duì)象。我們通過(guò)new的形式創(chuàng)建對(duì)象實(shí)際上就是通過(guò)這些Class來(lái)創(chuàng)建,只是這個(gè)過(guò)程對(duì)于我們是不透明的而已。
          反射的工作原理就是借助Class.java、Constructor.java、Method.java、Field.java這四個(gè)類(lèi)在程序運(yùn)行時(shí)動(dòng)態(tài)訪(fǎng)問(wèn)和修改任何類(lèi)的行為和狀態(tài)。

          反射實(shí)例

          分別演示三種獲取類(lèi)信息的方式、獲取當(dāng)前類(lèi)的所有方法和獲取當(dāng)前類(lèi)及其父類(lèi)的所有方法、獲取當(dāng)前類(lèi)的所有實(shí)例和獲取當(dāng)前類(lèi)及其父類(lèi)的所有實(shí)例、獲取父類(lèi)信息、獲取接口信息、比較反射方法和實(shí)例的性能差異等幾個(gè)方面:
          • 示例類(lèi):
          父類(lèi)Personon.java:

          package com.eebbk.reflectdemo;

          public class Person{
              String mName;
              String mSex;
              public int mAge;

              public Person(String aName, String aSex, int aAge) {
                  mName = aName;
                  mSex = aSex;
                  mAge = aAge;
              }

              public int getmAge(){
                  return mAge;
              }

              public void setmAge(int mAge){
                  this.mAge = mAge;
              }

              public String getmName(){
                  return mName;
              }

              public void setmName(String mName){
                  this.mName = mName;
              }

              public String getmSex(){
                  return mSex;
              }

              public void setmSex(String mSex){
                  this.mSex = mSex;
              }

              private String getDescription(){
                  return "黃種人";
              }
          }

          接口ICompany.java:

          package com.eebbk.reflectdemo;

          public interface ICompany{
              String getCompany();
          }

          子類(lèi)ProgramMonkey.java:

          package com.eebbk.reflectdemo;

          public class ProgramMonkey extends Person implements ICompany{
              String mLanguage = "C#";
              String mCompany = "BBK";

              public ProgramMonkey(String aName, String aSex, int aAge){
                  super(aName, aSex, aAge);
              }

              public ProgramMonkey(String language, String company, String aName, String aSex, int aAge){
                  super(aName, aSex, aAge);
                  mLanguage = language;
                  mCompany = company;
              }

              public String getmLanguage(){
                  return mLanguage;
              }

              public void setmLanguage(String mLanguage){
                  this.mLanguage = mLanguage;
              }

              private int getSalaryPerMonth(){
                  return 12306;
              }

              @Override
              public String getCompany(){
                  return mCompany;
              }
          }

          示例類(lèi)ReflectActivity.java:

          public class ReflectActivity extends Activity{
              @Override
              protected void onCreate(Bundle savedInstanceState){
                  super.onCreate(savedInstanceState);
                  setContentView(R.layout.activity_reflect_layout);
              }

              public void onClick(View v){
                  switch(v.getId()){
                      case R.id.getClassObjectBtnId:{
                          getClassObject();
                      }
                      break;
                      case R.id.getMethodInfoBtnId:{
                          getMethodInfo();
                      }
                      break;
                      case R.id.getFieldInfoBtnId:{
                          getFieldInfo();
                      }
                      break;
                      case R.id.getSuperClassInfoBtnId:{
                          getSuperClass();
                      }
                      break;
                      case R.id.getInterfaceInfoBtnId:{
                          getInterfaces();
                      }
                      break;
                      case R.id.compareMethodAndFieldBtnId:{
                          compareCallMethodAndField();
                      }
                      break;
                      default:{

                      }
                      break;
                  }
              }

              private void getClassObject(){
                  Class<?> classObject = null;

                  classObject = getClassObject_1();
                  LogE("classObject_1 name : " + classObject.getName());
                  classObject = getClassObject_2();
                  LogE("classObject_2 name : " + classObject.getName());
                  classObject = getClassObject_3();
                  LogE("classObject_3 name : " + classObject.getName());
              }

              private void getMethodInfo(){
                  getAllMethods();
                  getCurrentClassMethods();
              }

              private void getFieldInfo(){
                  getAllFields();
                  getCurrentClassFields();
              }

              private void getSuperClass(){
                  ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                  Class<?> superClass = programMonkey.getClass().getSuperclass();
                  while (superClass != null) {
                      LogE("programMonkey's super class is : " + superClass.getName());
                      // 再獲取父類(lèi)的上一層父類(lèi),直到最后的 Object 類(lèi),Object 的父類(lèi)為 null
                      superClass = superClass.getSuperclass();
                  }
              }

              private void getInterfaces() {
                  ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                  Class<?>[] interfaceses = programMonkey.getClass().getInterfaces();
                  for (Class<?> class1 : interfaceses) {
                      LogE("programMonkey's interface is : " + class1.getName());
                  }
              }

              private void compareCallMethodAndField(){
                  long callMethodCostTime = getCallMethodCostTime(10000);
                  LogE("callMethodCostTime == " + callMethodCostTime);
                  long callFieldCostTime = getCallFieldCostTime(10000);
                  LogE("callFieldCostTime == " + callFieldCostTime);
              }

              private long getCallMethodCostTime(int count){
                  long startTime = System.currentTimeMillis();
                  for(int index = 0 ; index < count; index++){
                      ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                      try{
                          Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);
                          setmLanguageMethod.setAccessible(true);
                          setmLanguageMethod.invoke(programMonkey, "Java");
                      }catch(IllegalAccessException e){
                          e.printStackTrace();
                      }catch(InvocationTargetException e){
                          e.printStackTrace();
                      }catch(NoSuchMethodException e){
                          e.printStackTrace();
                      }
                  }

                  return System.currentTimeMillis()-startTime;
              }

              private long getCallFieldCostTime(int count){
                  long startTime = System.currentTimeMillis();
                  for(int index = 0 ; index < count; index++){
                      ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                      try{
                          Field ageField = programMonkey.getClass().getDeclaredField("mLanguage");
                          ageField.set(programMonkey, "Java");
                      }catch(NoSuchFieldException e){
                          e.printStackTrace();
                      }catch(IllegalAccessException e){
                          e.printStackTrace();
                      }
                  }

                  return System.currentTimeMillis()-startTime;
              }

              /**
               * 獲取當(dāng)前類(lèi)中的所有方法
               *
               * */
              private void getCurrentClassMethods() {
                  ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                  Method[] methods = programMonkey.getClass().getDeclaredMethods();
                  for (Method method : methods) {
                      LogE("declared method name : " + method.getName());
                  }

                  try {
                      Method getSalaryPerMonthMethod = programMonkey.getClass().getDeclaredMethod("getSalaryPerMonth");
                      getSalaryPerMonthMethod.setAccessible(true);
                      // 獲取返回類(lèi)型
                      Class<?> returnType = getSalaryPerMonthMethod.getReturnType();
                      LogE("getSalaryPerMonth 方法的返回類(lèi)型 : " + returnType.getName());

                      // 獲取方法的參數(shù)類(lèi)型列表
                      Class<?>[] paramClasses = getSalaryPerMonthMethod.getParameterTypes() ;
                      for (Class<?> class1 : paramClasses) {
                          LogE("getSalaryPerMonth 方法的參數(shù)類(lèi)型 : " + class1.getName());
                      }

                      // 是否是 private 函數(shù),屬性是否是 private 也可以使用這種方式判斷
                      LogE(getSalaryPerMonthMethod.getName() + " is private " + Modifier.isPrivate(getSalaryPerMonthMethod.getModifiers()));

                      // 執(zhí)行方法
                      Object result = getSalaryPerMonthMethod.invoke(programMonkey);
                      LogE("getSalaryPerMonth 方法的返回結(jié)果: " + result);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

              /**
               * 獲取當(dāng)前類(lèi)和父類(lèi)的所有公有方法
               *
               * */
              private void getAllMethods() {
                  ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                  // 獲取當(dāng)前類(lèi)和父類(lèi)的所有公有方法
                  Method[] methods = programMonkey.getClass().getMethods();
                  for (Method method : methods) {
                      LogE("method name : " + method.getName());
                  }

                  try {
                      Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);
                      setmLanguageMethod.setAccessible(true);

                      // 獲取返回類(lèi)型
                      Class<?> returnType = setmLanguageMethod.getReturnType();
                      LogE("setmLanguage 方法的返回類(lèi)型 : " + returnType.getName());

                      // 獲取方法的參數(shù)類(lèi)型列表
                      Class<?>[] paramClasses = setmLanguageMethod.getParameterTypes() ;
                      for (Class<?> class1 : paramClasses) {
                          LogE("setmLanguage 方法的參數(shù)類(lèi)型 : " + class1.getName());
                      }

                      // 是否是 private 函數(shù),屬性是否是 private 也可以使用這種方式判斷
                      LogE(setmLanguageMethod.getName() + " is private " + Modifier.isPrivate(setmLanguageMethod.getModifiers()));

                      // 執(zhí)行方法
                      Object result = setmLanguageMethod.invoke(programMonkey, "Java");
                      LogE("setmLanguage 方法的返回結(jié)果: " + result);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

              private Class<?> getClassObject_1(){
                  return ProgramMonkey.class;
              }

              private Class<?> getClassObject_2(){
                  ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                  return programMonkey.getClass();
              }

              private Class<?> getClassObject_3(){
                  try{
                      return Class.forName("com.eebbk.reflectdemo.ProgramMonkey");
                  }catch(ClassNotFoundException e){
                      e.printStackTrace();
                  }

                  return null;
              }

              /**
               * 得到當(dāng)前類(lèi)的所有實(shí)例
               *
               * */
              private void getCurrentClassFields() {
                  ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                  // 獲取當(dāng)前類(lèi)的所有屬性
                  Field[] publicFields = programMonkey.getClass().getDeclaredFields();
                  for (Field field : publicFields) {
                      LogE("declared field name : " + field.getName());
                  }

                  try {
                      // 獲取當(dāng)前類(lèi)的某個(gè)屬性
                      Field ageField = programMonkey.getClass().getDeclaredField("mAge");
                      // 獲取屬性值
                      LogE(" my age is : " + ageField.getInt(programMonkey));
                      // 設(shè)置屬性值
                      ageField.set(programMonkey, 10);
                      LogE(" my age is : " + ageField.getInt(programMonkey));
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

              /**
               * 得到當(dāng)前類(lèi)和父類(lèi)的所有公有屬性
               *
               * */
              private void getAllFields() {
                  ProgramMonkey programMonkey = new ProgramMonkey("小明""男", 12);
                  // 得到當(dāng)前類(lèi)和父類(lèi)的所有公有屬性
                  Field[] publicFields = programMonkey.getClass().getFields();
                  for (Field field : publicFields) {
                      LogE("field name : " + field.getName());
                  }

                  try {
                      // 獲取當(dāng)前類(lèi)和父類(lèi)的某個(gè)公有屬性
                      Field ageField = programMonkey.getClass().getField("mAge");
                      LogE(" age is : " + ageField.getInt(programMonkey));
                      ageField.set(programMonkey, 8);
                      LogE(" my age is : " + ageField.getInt(programMonkey));
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

              private void LogE(String msg){
                  Log.e("Reflection""============== " + msg);
              }
          }

          • 演示結(jié)果:
          三種獲取類(lèi)信息的方式:
          獲取當(dāng)前類(lèi)的方法、獲取當(dāng)前類(lèi)和父類(lèi)的所有公有方法:
          獲取當(dāng)前類(lèi)的所有實(shí)例、獲取當(dāng)前類(lèi)和父類(lèi)的所有公有實(shí)例:
          獲取父類(lèi)信息:
          獲取接口信息:
          比較反射方法和實(shí)例的性能差異:
          通過(guò)上面的示例可以發(fā)現(xiàn),通過(guò)反射能夠完成之前所描述的事情,并且反射方法比反射實(shí)例要慢很多。

          反射的特點(diǎn)

          優(yōu)點(diǎn)

          • 靈活、自由度高: 不受類(lèi)的訪(fǎng)問(wèn)權(quán)限限制,想對(duì)類(lèi)做啥就做啥;

          缺點(diǎn)

          • 性能問(wèn)題: 通過(guò)反射訪(fǎng)問(wèn)、修改類(lèi)的屬性和方法時(shí)會(huì)遠(yuǎn)慢于直接操作,但性能問(wèn)題的嚴(yán)重程度取決于在程序中是如何使用反射的。如果使用得很少,不是很頻繁,性能將不會(huì)是什么問(wèn)題;

          • 安全性問(wèn)題: 反射可以隨意訪(fǎng)問(wèn)和修改類(lèi)的所有狀態(tài)和行為,破壞了類(lèi)的封裝性,如果不熟悉被反射類(lèi)的實(shí)現(xiàn)原理,隨意修改可能導(dǎo)致潛在的邏輯問(wèn)題;

          • 兼容性問(wèn)題: 因?yàn)榉瓷鋾?huì)涉及到直接訪(fǎng)問(wèn)類(lèi)的方法名和實(shí)例名,不同版本的API如果有變動(dòng),反射時(shí)找不到對(duì)應(yīng)的屬性和方法時(shí)會(huì)報(bào)異常;

          說(shuō)明

          • 通過(guò)反射訪(fǎng)問(wèn)方法比實(shí)例慢很多;

          • 有用到反射的類(lèi)不能被混淆;

          • 反射存在性能問(wèn)題,但使用不頻繁、按需使用時(shí),對(duì)程序性能影響并不大;

          • 反射存在安全性問(wèn)題,因?yàn)榭梢噪S意修改類(lèi)的所有狀態(tài)和行為(包括private方法和實(shí)例);

          • 使用反射訪(fǎng)問(wèn)Android的API時(shí)需要注意因?yàn)椴煌珹PI版本導(dǎo)致的兼容性問(wèn)題;

          <END>

          掃碼加入技術(shù)交流群,不定時(shí)送書(shū)

          推薦閱讀:

          【167期】面試官:反射是如何影響性能的,它到底慢在哪里?

          【166期】圖解ElasticSearch原理,搞懂它,面試再也不用怕被問(wèn)到了!

          【165期】面試官:你對(duì)MySQL分區(qū)的知識(shí)了解多少?

          5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機(jī),樹(shù)莓派,等等。在公眾號(hào)內(nèi)回復(fù)「2048」,即可免費(fèi)獲取??!

          微信掃描二維碼,關(guān)注我的公眾號(hào)

          朕已閱 

          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久亚洲一区女同性恋中文字幕 | 黑人大操逼 | 国内精品内射 | 日韩中文在线字幕 | 在线免费黄片 |