Android反射机制

2019-07-12  本文已影响0人  溫順尚早

Android反射相关知识汇总

一、什么是反射机制?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

官方文档上介绍:反射技术通常被用来检测和改变应用程序在Java虚拟机中的行为表现。它是一个相对而言比较高级的技术,通常它应用的前提是开发者本身对于Java语言特性有很强的理解的基础上。反射是一种强有力的技术特性,因此可以使得应用程序突破一些无法企及的目的。

二、我们需要知道哪些理论基础?

三、我们需要掌握哪些方法呢?

  1、类名.class; 不执行静态块和动态构造块。
  2、Class.forName(path); 执行静态块,不执行动态构造块。
  3、对象.getClass(); 需要创建对象,静态块和动态构造块均会执行。
  1、class.getField(fieldName); 只能获取public修饰的字段
  2、class.getFields(); 获取所有public修饰的字段的Field数组
  3、class.getDeclaredField(fieldName); 可以获得所有字段
  4、class.getDeclaredFields(); 获取所有字段的Field数组
  1、class.getMethod(methodName); 只能获取public修饰的方法名称
  2、class.getMethods(); 获取所有public修饰的方法的Method数组
  3、class.getDeclaredMethod(methodName); 可以获得所有方法
  4、class.getDeclaredMethods(); 获取所有方法的Method数组
  1、class.getConstructor(methodName); 只能获取public修饰的方法名称
  2、class.getConstructors(); 获取所有public修饰的方法的Method数组
  3、class.getDeclaredConstructor(methodName); 可以获得所有方法
  4、class.getDeclaredConstructors(); 获取所有方法的Method数组
  1、Constructor.newInstance(可变参数);
  eg:Persion p = (Persion)constructor.newInstance("1");
(1) field.set(Objkect obj,Object value);
(2) field.setInt(Objkect obj,int value);
...
(n) file.setLong(Objkect obj,long value);
(1) field.get(Object);
eg:Person p = (Persion)filed.get(对象);
这里必须注意的是当操作的对象用private修饰的时候需要用method.setAccessible(true)来设置可以访问到.
然后调用method.invoke(Object obj,参数),这个Object的对象必须是该类的对象.不是所谓的类对象.

四.Android能用到的地方

Class<? extends TabLayout> tabClass = tabLayout.getClass();
     try {
         Field mTabStrip = tabClass.getDeclaredField("mTabStrip");
         mTabStrip.setAccessible(true);
        LinearLayout linearLayout = (LinearLayout) mTabStrip.get(tabLayout);
         for (int i = 0; i < linearLayout.getChildCount(); i++) {
             View child = linearLayout.getChildAt(i);
             child.setPadding(0,0,0,0);
             LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) child.getLayoutParams();
            // layoutParams.width = 300;
             layoutParams.leftMargin = 150;
             layoutParams.rightMargin = 150;
             child.setLayoutParams(layoutParams);
             child.invalidate();
         }
     } catch (NoSuchFieldException e) {
         e.printStackTrace();
     } catch (IllegalAccessException e) {
         e.printStackTrace();
     }

这里系统自带的Toast只给了我们两个时间的选择SHORT_DURATION_TIMEOUT和LONG_DURATION_TIMEOUT其他的我们没法改变.还好系统提供了hide方法不过在外面我们是访问不到,这里我们也可以用到反射,大部分的操作都是Toast的内部类TN来完成的.首先获取到Toast的class对象,Toast内部含有内部类的字段(final TN mTN),这样我们可以获取到内部类的对象,然后再通过内部类的Class对象来获取内部类里面的hide()方法.代码如下:

mParams.hideTimeoutMilliseconds = mDuration ==
  Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
               ...
  /**
    * schedule handleHide into the right thread
    */
   @Override
   public void hide() {
       if (localLOGV) Log.v(TAG, "HIDE: " + this);
       mHandler.obtainMessage(HIDE).sendToTarget();
   }
  try{
       Class<Toast> toastClass = Toast.class;
       Field mTN = toastClass.getDeclaredField("mTN");
       //获取修饰符类型
       toastClass.getModifiers();
       mTN.setAccessible(true);
       Object o = mTN.get(toast);
       Class<?> aClass = o.getClass();
       Method hide = aClass.getDeclaredMethod("hide");
       hide.setAccessible(true);
       hide.invoke(o);
   } catch (NoSuchFieldException e) {
       e.printStackTrace();
   } catch (IllegalAccessException e) {
       e.printStackTrace();
   } catch (InvocationTargetException e) {
       e.printStackTrace();
   } catch (NoSuchMethodException e) {
       e.printStackTrace();
   }
上一篇 下一篇

猜你喜欢

热点阅读