JavaSE——反射机制(二)

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。

Class管理类的其他方法

类的结构如下:

这里将类的结构划分开来了,m表示方法method,f表示属性filed,没有标识返回值的方法表示是构造器

绿色的锁表示权限公开public,红色的锁表示权限私有private

接下来将使用反射机制对类的构造(f,m)全部操作一遍,不论属性或方法,私有或其他权限!

代码示例:

第一件事情,加载类:

Class cls = Class.forName("com.kaige123.daomu.Dog");

可以做的操作:

实例化对象:

1:Object obj = cls.newInstance();

得到的是Dog类对象

2:查看这个实例化对象的方法,如果是有参构造器怎么解决?

解决办法:

Constructor constructor = cls.getConstructor(String.class, String.class, int.class);

Object object = constructor.newInstance("小黑狗", "旺财", 1);

getConstructor搜索到某个构造器,返回构造器对象,newInstance实例化出对象

搜索构造器的参数,需要明确:

构造器以及方法不能靠名字搜索因为:重载。需要靠名字以及参数类型和个数定位到方法

这里面是集合参数Class<T>...于是这里的搜索:可以传多个类型的class。他通过传递的类型class以及个数,找到构造器,返回构造器对象,如果找不到抛找不到异常。

如果是基本数据类型,也是传int.class....其他基本数据类型也是

返回构造器对象后,通过构造器对象.newInstance实例化Dog对象

这里介绍了两种实例化对象的方法:有参无无参构造器。无参newInstance实例化,有参找到构造器newInstance实例化。

对象可以实例化出一份。但forName加载的类只有一份。类模板只有一份,重复加载,也是使用加载过的这个类。但对象可以创建出多个。这两个观点不冲突。

操作方法:

实例化出Dog对象,如何操作方法?返回的实例对象Object要转子类吗?并不是的,如果转子类,又回到死代码。

如果子类有独特的方法,父类没有声明,怎么办?需要明确一点,转了子类,再次依赖子类,死代码。想办法划分多个声明,转子类的父类声明也比转子类强。这里按照情况斟酌办法。

这里操作方法代码是:

cls.getMethod指定搜索某个方法,返回方法对象。

这里也需要明确:方法不能仅靠名字判断,因为重载。还需要参数类型以及参数个数。

getMethod(name,paramter...)方法的名字,集合参数(可以传递n个参数)根据方法的名字,参数的类型以及个数,定位到方法,类型以及个数可以避免方法重载的情况

搜索到方法后,返回的方法对象method。

如果是静态方法,发起调用method.invoke(null,null)

如果是实例方法,发起调用method.invoke(object,null)

如果是实例有参方法,发起调用method.invoke(object,param...)

invoke调用方法:前面是调用谁的方法,后面是给方法传递的参数(需:方法有参)

如果是静态,当cls.getmethod在invoke,第一个参数传递null,表示cls类的调用 如果是实例,当cls.getmethod在invoke,第一个参数传递对象,表示对象的调用 如果是有参,invoke传递参数,无参则null。传递的参数给方法形参接收,不是传class

静态传null,表示是类发起调用。如果是实例方法,就需要传递对象,使用对象发起调用。当然静态传对象也行,表示用对象调用静态方法。

如果方法有返回值,前面写上接收的变量即可。 如果方法有形参,paramterType写上类型.class。便于从重载中定位。

我们不难发现,在搜索构造器与方法都有一个参数,那就是paramterType...参数类型(集合)。因为单靠名字不敢搜索,还需要参数的类型以及个数。

这个paramterType是集合参数,我们可以一直往后面添加类型.class。但我们这样直接往后面添加参数可取吗?

不可取!这样直接写不可变!这个应该随要搜索的方法走,要搜索出不同的方法,这里要变!这里的集合参数,不仅是可以直接往后面传参,集合要求可以接收数组类型!我们为了灵活应该使用数组,随需求可以改改,这样可以搜索出不同的方法,如果写参数就定死了!

实例:

Class[] classes = new Class[]{String.class, String.class, int.class};

Constructor constructor = cls.getConstructor(classes);

避免直接给方法传类型.class,来寻找。这样是死的,很明显。当我们使用数组,数组可以随我们改变,于是这样后就可以随着数组的class及个数变化而能搜索出不同的方法。

操作私有属性:

我们从类的构造中,可以得到age属性是私有的

从类中搜索属性:

搜索公开属性:cls.getField(name)

搜索私有属性:cls.getDeclaredField(name)

于属性来说,没有像方法一样,方法可能存在方法重载,需要靠方法名字以及方法参数类型及个数来定位方法。而属性在整个类来说,凭属性名就能定位到属性了。

于是搜索只需要属性名即可,从Class类中搜索,不依靠不对Object操作。这是Dog类这也是Object类。如果直接对Object也便于于以后操作。这里使用反射还能灵活的搜不同属性。

从Class类Dog类的管理类搜索出属性后,这是一个私有属性,如何操作?

首先需要setAccessible,true设置对私有属性产生操作

当设置这个后,就可以直接操作这个搜索出来的属性了。返回的Field对象

比如:

能不经过setAge方法直接给属性赋值。Set(object,value);

能不经过getAge方法获得属性赋值。get(object);

如果是静态属性,则不需要object获得的实例对象。表示从类发起操作

如果是实例属性。则需要传入实例的对象。表示从对象发起操作

操作公开也是这样,不过方法改为getFiled即可。也不需要设置setAccessible权限。

操作私有方法:

操作私有方法也是雷同,getDeclanMethod搜索私有方法,setAccessible设置权限,在操作。

总结:

实例化对象,分有参无参构造器:

无参可以直接使用Class类的管理类调用实例化方法,从类中加载一个对象出来。

有参需要从Class管理类(=Doge)类搜索到指定构造器,由构造器对象构造对象出来。

操作公开方法:

Class.getMethod(name,...)根据名字与参数类型个数,拿到找到的方法对象

Invoke(obj,value)调用方法:如果是静态可以不传对象(由类)。如果是实例需要传对象(由对象)。

如果方法有返回值,在invoke前准备接收的变量接收。

操作私有的方法,与前面大致一致,额外改变:

由getMethod改成getDeclareMethod。在invoke前Method.setAccessible让私有允许调用

操作公开属性,与操作方法一致,额外改变:

getField(name);根据属性名就能搜到属性,返回Field对象。

属性可以Field.get(obj)得到值,可以Field.set(obj,value)设置值。

如果是静态属性,则不需要obj由类对Filed对象发起操作

如果是实例属性,则需要obj由对象对Filed对象发起操作

操作私有属性,与前面大致一致,额外改变:

由getField改成getDeclareField。在操作前Field.setAccessible让私有属性允许操作

观察,实例化返回Object基本没有任何操作。我们的操作是通过Class锁定要操作的对象,进行操作。Object让他一直保持父类,由类的管理类操作对象。

当给实例属性或方法赋值,才需要obj实例后对象帮忙。因为一个加载的类,可以构建出多个对象,不知道给哪个对象赋值。我们赋值也保持Object父类,通过Class管理类传递对象,给对象上赋值,将一直保持Object类,通过Class对Object对象及类操作。都是为了灵活。

搜索方法是集合参数,因为单靠名字无法确定方法,构造器也是。需要靠方法需求的参数类型.class再靠集合参数的个数定位到方法,构造器也是。集合参数我们不直接写参数的class,通常是传递写好的Class[]过去。为了可变,改变数组引用,就能搜索不同的实例。

需要明确一点,我们不直接操作对象,通过Class管理类,搜索到操作的对象。如果是静态,直接操作表示由Class操作。如果是实例传递obj对象,表示要操作这个对象的这个实例。传递对象因为一个类可以造多个对象。需要明确类模板只有一个。

他静态与实例的关系如下图:

如果是null,反正搜索我Field的对象是Class,表示是得到Class身上的静态属性

如果是obj,表示是得到对象身上的这个Field对象属性的值。

这就是传null与obj的区别,一个是从类操作,一个从传递的对象身上操作对象。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,148评论 0 9
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 8,020评论 6 13
  • #还乡手记# 一个教师的返乡手记 我的老家在豫南盆地的一个县城唐河。这里是中国哲学大师冯友兰的故乡,冯友兰都不用介...
    山上石头阅读 1,378评论 4 8
  • 第一次发文,略激动。真实原创 事情是这样,我是一个热血质的微胖女生。因为我想减肥,所以当我看到每天晚上操场上热闹的...
    风淡淡的吹过阅读 213评论 2 2
  • 最近几部迪士尼的动画风格与以前迥然不同,每一部的内容都愈发的深刻,不再是那种王子公主的简易格局,而是朝着多元化的方...
    尚巾林阅读 190评论 0 0
  • 人都会有期待,期待会让人在日常的琐碎中活得轻松一些。可有时期待着的后面迎来的是失望的话,那么还不如不要有期待会更好...
    桃木小妖阅读 346评论 0 0