Java反射知识小结

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

  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,可以向下强转。


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容

  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,651评论 0 11
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,657评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,631评论 18 399
  • 我这一生,许多不幸,许多心酸。曾经背负着克星,煞星,我也不曾低头过。我的出生,没有喜悦与祝福,而是斥责与谩骂,...
    青冥杳兮阅读 240评论 0 0
  • 人生为了什么,才有这样凄凉的夜。 ——萧红 人生是漫长的,特别是对于穷人来说,他们不仅仅要...
    一纪重华阅读 511评论 0 4