Android 反射机制

 

一、什么是反射机制?

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

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

 

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

  • Class:Class对象是一个特殊的对象,是用来创建其它Java的实例,Class对象就是Java类编译后生成的.class文件,它包含了与类有关的信息。

  • Field:Filed字段提供有关和动态访问的信息,类或接口的单个字段。反射的字段可能是类字段或实例字段。

  • Method:Method方法提供了关于单个方法的信息和访问在类或接口上。反射的方法可能是类方法或者是一个实例方法(包括一个抽象的方法)。

  • Constructor:Constructor提供了关于某类的构造方法的所需信息。

  •  

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

  • 获取Class对象的几个方法:

  1、类名.class; 不执行静态块和动态构造块。  2、Class.forName(path); 执行静态块,不执行动态构造块。  3、对象.getClass(); 需要创建对象,静态块和动态构造块均会执行。
  • 获取类属性Field的几个方法:

  1、class.getField(fieldName); 只能获取public修饰的字段  2、class.getFields(); 获取所有public修饰的字段的Field数组  3、class.getDeclaredField(fieldName); 可以获得所有字段  4、class.getDeclaredFields(); 获取所有字段的Field数组
  • 获取类方法Method的几个方法:

  1、class.getMethod(methodName); 只能获取public修饰的方法名称  2、class.getMethods(); 获取所有public修饰的方法的Method数组  3、class.getDeclaredMethod(methodName); 可以获得所有方法  4、class.getDeclaredMethods(); 获取所有方法的Method数组
  • 获取构造函数Constructor的几个方法:

  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能用到的地方

  • 修改TabLayout的下划线的长度.对于TabLayout的使用这里就不必多说了,系统只提供了修改下划线的高度和颜色的方法,并没有修改长度的方法.这里就要用到反射区获取TabLayout内部控制长度的方法.这里只能通过设置每个Tab的Margin来控制下划线的宽度,有可能出现Tab的文字被挤压的情况,只能将就使用了.代码如下:

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的显示时间.Toast内部类TN的设置显示时间的代码:

这里系统自带的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 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();   }

 

更多相关文章

  1. Cursor与Adapter结合使用
  2. Android(安卓)UI开发——使用Fragment构建灵活的桌面
  3. Android:分析app、Process、Task之间的区别,以及获取最近运行的程
  4. Android中关于JNI 的学习(零)简单的例子,简单地入门
  5. 我的第一个Android升级版本
  6. 从一道面试题开始说起 枚举、动态代理的原理
  7. Android实现异步处理 -- HTTP请求为例
  8. Android(安卓)面试题(有详细答案)
  9. Android(安卓)Handler消息处理机制详解

随机推荐

  1. android DDMS 连接真机(己ROOT),用file exp
  2. Android(安卓)Studio3.3.2+gradle 3.3.2
  3. Android改变ExpandableListView的indicat
  4. Android Handler 的工作原理解析
  5. android系统中的多线程(一): 关于在andro
  6. Android基础入门教程——3.1 基于监听的
  7. [android]-如何在向服务器发送request时
  8. android绘图之Canvas基础(2)
  9. Android中handler的使用及原理---学习笔
  10. Google 发布的15个 Android 性能优化典范