Java反射知识小结

作者: 陈利健 | 来源:发表于2015-02-26 21:54 被阅读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)方法中的两个参数:

    • 第一个参数是方法名,第二个参数是该方法的参数类型数组
    • 因为存在同方法名不同参数这种情况,所以只有同时指定方法名和参数类型才能唯一确定一个方法。
      如一个函数: int test(int a, String str);
      对应的getMethod方法:
      getMethod("test",int.class, String.class);
      或:getMethod("test",new Class[]{ int.class, String.class } );

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

    • 前者是该方法参数的实际的值。
    • 后者是该方法参数的实际的值的参数类型。

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


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

    相关文章

      网友评论

        本文标题:Java反射知识小结

        本文链接:https://www.haomeiwen.com/subject/iejpxttx.html