Android开发经验笔记加油站思维集

Java反射知识小结

2015-02-26  本文已影响790人  陈利健

反射知识在我近期的开发中用到的不过,所以知识点也不是很清楚。今天补习了一下反射部分内容,在这里做一个小结。

  1. Java反射的概念
      反射含义:可以获取正在运行的Java对象。

  2. Java反射的功能
      1)可以判断运行时对象所属的类
      2)可以判断运行时对象所具有的成员变量和方法
      3)通过反射甚至可以调用到private的方法
      4)生成动态代理

  3. Java反射机制

    • 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
      对于任意一个对象,都能够调用它的任意一个方法;
      这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    • Java反射机制主要提供了以下功能:
      在运行时判断任意一个对象所属的类;
      在运行时构造任意一个类的对象;
      在运行时判断任意一个类所具有的成员变量和方法;
      在运行时调用任意一个对象的方法;
      生成动态代理。
  4. 实现Java反射的类
      1) Class:它表示正在运行的Java应用程序中的类和接口
      2) Field:提供有关类或接口的属性信息,以及对它的动态访问权限
      3) Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
      4) Method:提供关于类或接口中某个方法信息
      注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/ 属性/构造方法/访问权限)都需要它来实现。

  5. 编写Java反射程序的步骤:
      1) 必须首先获取一个类的Class对象
      例如(推荐第一种):
      Class c1 = Test.class;
      Class c2 = Class.forName(“com.reflection.Test”);
      Class c3 = new Test().getClass();
      2) 然后分别调用Class对象中的方法来获取一个类的属性/方法/构造方法的结构
      注意:如果要能够正常的获取类中方法/属性/构造方法应该重点掌握如下的反射类
      Field
      Constructor
      Method


常用方法

//首先要获取一个类的Class对象
Class c1 = TestReflection.class;
或:Class<Bean> c1 = (Class<Bean>) Class.forName(className);
或:Class<Bean> c1 = (Class<Bean>) new Bean().getClass();

//生成一个实例 
Bean b = (Bean)c1.newInstance(); 

//获取指定的包名
String package01 = c1.getPackage().getName();
//获取类的修饰符
int mod = c1.getModifiers();
//获取指定类的完全限定名
String className = c1.getName();
//获取指定类的父类
Class superClazz = c1.getSuperclass();
//获取实现的接口
Class[] interfaces = c1.getInterfaces();


//获取指定类的所有成员变量:(类或接口所声明的所有字段,public, private, protected ,但不包括从基类继承的字段)
Field[] fields = c1.getDeclaredFields();

for (Field field : fields) {    
    //获取每个字段的访问修饰符
  modifier = Modifier.toString(field.getModifiers()); 
    //获取字段的数据类型所对应的Class对象
  Class type = field.getType(); 
    //获取字段名
  String name = field.getName(); 

    //如果是数组类型则需要特别处理
  if (type.isArray()) { 
    String arrType = type.getComponentType().getName() +"[]";
    System.out.println("" + modifier + " " + arrType + " "+ name + ";");
  } else {
    System.out.println("" + modifier + " " + type + " " + name + ";");
  }
}

//获取指定类的指定成员变量(前者为全部,后者仅为公有,但包含基类)
Field field = c1.getDeclaredField("mScroller");
Field field = c1.getField("mScroller");

实例(获取指定类的指定成员变量):
初始化ViewPager时,利用获得指定成员变量,来反射修改滑动速度。

public class ViewPagerScroller extends Scroller {
    
    // 设置滑动速度
    private int mScrollDuration = 2000;             
 
    public void setScrollDuration(int duration){
        this.mScrollDuration = duration;
    }
     
    public ViewPagerScroller(Context context) {
        super(context);
    }
 
    public ViewPagerScroller(Context context, Interpolator interpolator) {
        super(context, interpolator);
    }
 
    public ViewPagerScroller(Context context, Interpolator interpolator, boolean flywheel) {
        super(context, interpolator, flywheel);
    }
 
    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        super.startScroll(startX, startY, dx, dy, mScrollDuration);
    }
 
    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        super.startScroll(startX, startY, dx, dy, mScrollDuration);
    }
      
    public void initViewPagerScroll(ViewPager viewPager) {
        try {
            //在这里使用了反射,获得ViewPager类的指定成员变量
            Field mScroller = ViewPager.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            //将ViewPager的实例,即传入作为形参的viewPager对象,也就是主界面程序中的mViewPager对象,中的成员变量mScroller设置为this
            mScroller.set(viewPager, this);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

    //在主界面程序中使用ViewPager的时候,这样初始化:
     mViewPager = (ShowViewPager) getActivity().findViewById(R.id.viewpager);
     ViewPagerScroller viewPagerScroller = new ViewPagerScroller(getActivity());
     viewPagerScroller.initViewPagerScroll(mViewPager);

获取指定类的所有方法的两种方式:
public Method[] getMethods():返回某个类的所有public方法,包括从基类继承的、从接口实现的所有public方法。
public Method[] getDeclaredMethods():返回某个类自身声明的所有方法(public, private, protected),包括从所实现接口的方法,但不包括继承的方法。


getMethod获取指定方法的用法举例:

public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {  
   
     //首先得到这个对象的Class
     Class ownerClass = owner.getClass();  
   
     //配置参数的Class数组,作为寻找Method的条件
     Class[] argsClass = new Class[args.length];
     for (int i = 0, j = args.length; i < j; i++) {  
         argsClass[i] = args[i].getClass();  
     }  
  
     //得到要执行的Method
     Method method = ownerClass.getMethod(methodName,argsClass);  
   
     //执行该Method.invoke方法的参数是执行这个方法的对象owner,和参数数组args。可以这么理解:owner对象中带有参数args的method方法。返回值是Object,也既是该方法的返回值。
     return method.invoke(owner, args);  
}  
public Object invokeStaticMethod(String className, String methodName,  
             Object[] args) throws Exception {  
    Class ownerClass = Class.forName(className);  
   
    Class[] argsClass = new Class[args.length];  
    for (int i = 0, j = args.length; i < j; i++) {  
         argsClass[i] = args[i].getClass();  
    }  
   
    Method method = ownerClass.getMethod(methodName,argsClass);  
   
    //invoke的一个参数是null,因为这是静态方法,不需要借助实例运行
    return method.invoke(null, args);  
 }

解释一下getMethod(String name, Class<?>... parameterTypes)方法中的两个参数:


method.invoke(Object receiver, Object... args)
就是最后一步:执行改类的指定方法了。
需要注意的是其第二个参数,不同于getMethod的第二个参数。

invoke方法的返回值即为该方法实际的返回值类型,包装成Object,可以向下强转。


已上面的例子为例引出一个疑问:

上一篇下一篇

猜你喜欢

热点阅读