版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第12章Java反射机制·反射的概念·Class类·反射的使用12.1反射概述Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以得到任意一个对象所属的类的信息,可以调用任意一个类的成员变量和方法,可以获取任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。12.1反射概述反射机制的优点是可以实现动态创建对象和编译(即动态编译),特别是在J2EE的开发中,反射的灵活性表现的十分明显。例如,一个大型的软件,不可能一次就把程序设计的很完美,当这个程序编译、发布上线后,如果需要更新某些功能,我们不可能要用户把以前的软件卸载,再重新安装新的版本。这时,如果采用静态编译,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制,程序可以在运行时动态的创建和编译对象,不需要用户重新安装软件,即可实现功能的更新。12.2认识Class类Java程序的运行机制,JVM编译.java文件生成对应的.class文件,然后再将.class文件加载到内存中执行。在执行.class文件的时候可能需要用到其他类(其他.class文件内容),这个时候就需要获取其他类的信息(反射)。JVM在加载.class文件时,会产生一个java.lang.Class对象代表该.class字节码文件,从该Class对象中可以获得类的信息。因此要想完成反射操作,就必须先认识Class类。12.2认识Class类Class是JDK定义的类,它提供了很多方法,通过调用Class类的成员方法可以获取Class对象中的信息(.class文件中的类信息)。Class类的常用方法如下表。方法描述publicstaticClass<?>forName(StringclassName)throwsClassNotFoundException传入完整的“包.类”名称实例化Class对象publicConstructor[]getConstructors()throwsSecurityException得到一个类中的全部构造方法publicField[]getDeclaredFields()throwsSecurityException得到本类中单独定义的全部属性publicField[]getFields()throwsSecurityException取得本类继承而来的全部属性12.2认识Class类方法描述publicMethod[]getMethods()throwsSecurityException得到一个类中的全部方法publicMethodgetMethod(Stringname,Class...parameterType)throwsNoSuchMethodException,SecurityException返回一个Method对象,并设置一个方法中的所有参数类型publicClass[]getInterfaces()得到一个类中所实现的全部接口publicStringgetName()得到一个类完整的“包.类”名称publicPackagegetPackage()得到一个类的包publicClassgetSuperclass()得到一个类的父类publicObjectnewInstance()throwsInstantiationException,IllegalAccessException根据Class定义的类实例化对象publicClass<?>getComponentType()返回表示数组类型的ClasspublicbooleanisArray()判断此Class是否是一个数组12.2认识Class类由于Class对象代表的是.class文件(类),因此可以说所有的类实际上都是Class类的实例,所有的对象都可以转变为Class类型表示。实例化Class对象共有以下三种方式:(1)根据类名获取:类名.class;(2)根据对象获取:对象.getClass();(3)根据全限定类名获取:Class.forName(“全限定类名”)。12.2认识Class类Class类本身没有定义任何的构造方法,所以如果要使用Class类,必须通过上述三种方式进行实例化。接下来,通过一个案例演示Class类的上述三种实例化方式。1classA{2}3classExample01{4publicstaticvoidmain(Stringargs[]){5Class<?>c1=null;6Class<?>c2=null;7Class<?>c3=null;
12.2认识Class类8try{9c1=Class.forName("cn.itcast.A");10}catch(ClassNotFoundExceptione){11e.printStackTrace();12}13c2=newA().getClass();14c3=A.class;15System.out.println("类名称:"+c1.getName());16System.out.println("类名称:"+c2.getName());17System.out.println("类名称:"+c3.getName());18}19}12.2认识Class类上述代码中,第9行代码使用forName()方法实例化Class对象c1,第13行代码使用对象.getClass()的方式实例化Class对象c2,第14行代码使用类名.class的方式实例化Class对象c3。从图12-3的运行结果可以发现,3种实例化Class对象的结果是一样的,但是使用forName()方法实例化Class对象只需要将类的全限定类名以字符串作为参数传入即可,这让程序具备了更大的灵活性,所以使用forName()方法实例化Class对象是较为常用的一种方式,读者应重点掌握。12.2认识Class类程序运行结果如下图。12.3Class类的使用了解了Class类的实例化过程,那么到底该如何去使用Class类呢?实际上Class在开发中最常见的用法就是将Class类对象实例化为自定义类对象,即可以通过一个给定的字符串(类的全限定类名)实例化一个本类的对象。将Class对象实例化为本类对象时,可以通过无参构造完成,也可以通过有参构造完成。12.3.1通过无参构造实例化对象如果想通过Class类实例化其他类的对象,则可以使用newInstance()方法,但是必须要保证被实例化的类中存在一个无参构造方法。接下来通过一个案例演示Class类通过无参构造实例化对象。1classPerson{2privateStringname;3privateintage;4publicStringgetName(){5returnname;6}7publicvoidsetName(Stringname){8=name;9}
10publicintgetAge(){11returnage;12}13publicvoidsetAge(intage){14this.age=age;15}16publicStringtoString(){17return"姓名:"++",年龄:"+this.age;18}12.3.1通过无参构造实例化对象19classExample02{20publicstaticvoidmain(Stringargs[]){21Class<?>c=null;22try{23c=Class.forName("cn.itcast.Person");24}catch(ClassNotFoundExceptione){25e.printStackTrace();26}27Personper=null;
28try{29per=(Person)c.newInstance();30}catch(Exceptione){31e.printStackTrace();32}33per.setName("张三");34per.setAge(30);35System.out.println(per);36}37}12.3.1通过无参构造实例化对象程序运行结果如下图。12.3.1通过无参构造实例化对象上述代码中,第1~19行代码创建了一个Person类,在Person类中定义了name和age属性。第24行代码是通过Class.forName()方法实例化Class对象,第30行代码是使用Class对象c调用newInstance()方法并传入的完整“包.类”名称,对Person对象进行实例化操作。12.3.1通过无参构造实例化对象在使用newInstance()方法实例化类对象时,被实例化对象的类中必须存在无参构造方法,否则无法实例化对象。注意12.3.1通过无参构造实例化对象接下来演示没有无参构造方法时,通过newInstance()方法实例化对象。1classPerson{2privateStringname;3privateintage;4publicPerson(Stringname,intage){5this.setName(name);6this.setAge(age);7}8publicStringgetName(){9returnname;10}11publicvoidsetName(Stringname){12=name;13}14publicintgetAge(){15returnage;16}17publicvoidsetAge(intage){18this.age=age;19}20publicStringtoString(){21return"姓名:"++",年龄:"+this.age;22}23}12.3.1通过无参构造实例化对象24classExample03{25publicstaticvoidmain(Stringargs[]){26Class<?>c=null;27try{28c=Class.forName("cn.itcast.Person");29}catch(ClassNotFoundExceptione){30e.printStackTrace();31}32Personper=null;33try{34per=(Person)c.newInstance();35}catch(Exceptione){36e.printStackTrace();37}38}39}12.3.1通过无参构造实例化对象程序运行结果如下图。12.3.1通过无参构造实例化对象因为Person类中并没有存在无参构造方法,所以第35行代码对Person对象进行实例化时,无法直接使用newInstance()方法实例化的。由运行结果可知,报错信息提示Person类中没有发现无参构造方法,无法使用newInstance()方法实例化Person对象。因此,在使用Class类实例化对象时一定要在类中编写无参构造方法。12.3.2通过有参构造实例化对象如果类中没有无参构造方法,则可以通过有参构造方法实例化对象。通过有参构造方法实例化对象时,需要明确调用的构造方法,并传递相应的参数。通过有参构造方法实例化对象的操作步骤如下:(1)通过Class类中的getConstructors()方法获取本类中的全部构造方法。(2)向构造方法中传递一个对象数组,对象数组里面包含构造方法中所需的各个参数。(3)通过Constructor类实例化对象。12.3.2通过有参构造实例化对象上述操作步骤中使用了Constructor类,Constructor类用于存储本类的构造方法。Constructor类的常用方法如下表。方法描述publicintgetModifiers()得到构造方法的修饰符publicStringgetName()得到构造方法的名称publicClass<?>[]getParameterTypes()得到构造方法中参数的类型publicStringtoString()返回此构造方法的信息publicTnewInstance(Object...initargs)throwsInstantistionException,IllegalAccessException,IllegalArgumentException,InvocationTargetException向构造方法中传递参数,实例化对象12.3.2通过有参构造实例化对象接下来,通过一个案例讲解使用有参构造实例化对象。1importjava.lang.reflect.Constructor;2classPerson{3privateStringname;4privateintage;5publicPerson(Stringname,intage){6this.setName(name);7this.setAge(age);8}9publicStringgetName(){10returnname;11}12publicvoidsetName(Stringname){13=name;14}15publicintgetAge(){16returnage;17}18publicvoidsetAge(intage){19this.age=age;20}21publicStringtoString(){22return"姓名:"++",年龄:"+this.age;23}24}25classExample04{26publicstaticvoidmain(Stringargs[]){27Class<?>c=null;
12.3.2通过有参构造实例化对象28try{29c=Class.forName("cn.itcast.Person");30}catch(ClassNotFoundExceptione){31e.printStackTrace();32}33Personper=null;34Constructor<?>cons[]=null;35cons=c.getConstructors();36try{37per=(Person)cons[0].newInstance("张三",30);38}catch(Exceptione){39e.printStackTrace();40}41System.out.println(per);42}43}12.3.2通过有参构造实例化对象上述代码中,第5~8行代码定义了Person类的有参构造方法。第34~35行代码通过Class类取得了Person类中全部构造方法,并以对象数组的形式返回。第27行代码调用了Person类中的构造方法,而在Person类中只有一个构造方法,所以直接取出对象数组中的第一个元素即可(下表为0就表示调用第一个构造方法)。在声明对象数组时,必须考虑到构造方法中参数的类型顺序,所以第一个参数的类型为String,第二个参数的类型为Integer。12.3.2通过有参构造实例化对象程序运行结果如下图。12.4反射的作用在实际开发中,通过反射可以得到一个类的完整结构,包括类的构造方法、类的属性、类的方法,这就需要使用到java.lang.reflect包中的以下几个类:(1)Constructor:表示类中的构造方法。(2)Field:表示类中的属性。(3)Method:表示类中的方法。12.4反射的作用Constructor、Field、Method都是AccessibleObject类的子类。12.4.1获取所实现的全部接口要取得一个类所实现的全部接口,必须使用Class中的getInterfaces()方法。getInterfaces()方法声明如下:publicClass[]getInterfaces();getInterfaces()方法返回一个Class类的对象数组,调用Class类中的getName()方法可以取得类的名称。12.4.1获取所实现的全部接口接下来通过一个案例讲解通过getInterfaces()方法获取一个类所实现的全部接口。1interfaceChina{2publicstaticfinalStringNATION="CHINA";3publicstaticfinalStringAUTHOR="张三";4}5classPersonimplementsChina{6privateStringname;7privateintage;8publicPerson(Stringname,intage){9this.setName(name);10this.setAge(age);11}
12publicStringgetName(){13returnname;14}15publicvoidsetName(Stringname){16=name;17}18publicintgetAge(){19returnage;20}21publicvoidsetAge(intage){22this.age=age;23}12.4.1获取所实现的全部接口24publicStringtoString(){25return"姓名:"++",年龄:"+this.age;26}27}28publicclassExample05{29publicstaticvoidmain(Stringargs[]){30Class<?>c=null;12.4.1获取所实现的全部接口31try{32c=Class.forName("cn.itcast.Person");33}catch(ClassNotFoundExceptione){34e.printStackTrace();35}36Class<?>cons[]=c.getInterfaces();37for(inti=0;i<cons.length;i++){38System.out.println("实现的接口名称:"+cons[i].getName());39}40}41}12.4.1获取所实现的全部接口上述代码中,第1~4行代码定义了一个China接口,第5~27行代码定义了一个Person类并实现了China接口。因为接口是类的特殊形式,而且一个类可以实现多个接口,所以,第36~39行代码以Class数组的形式将全部的接口对象返回,并利用循环的方式将内容依次输出。由图12-6可知,Person类实现了China接口。12.4.1获取所实现的全部接口程序运行结果如下图。12.4.2获取全部方法要取得一个类中的全部方法,可以使用Class类中的getMethods()方法,该方法返回一个Method类的对象数组。如果想要进一步取得方法的具体信息,如方法的参数、抛出的异常声明等,就必须依靠Method类。12.4.2获取全部方法Method类的常用方法如下表。方法描述publicintgetModifiers()得到本方法的修饰符publicStringgetName()得到方法的名称publicClass<?>[]getParameterTypes()得到方法的全部参数的类型publicClass<?>getReturnType()得到方法的返回值类型publicClass<?>[]getExceptionType()得到一个方法的全部抛出异常publicTnewInstance(Object...initargs)throwsInstantistionException,IllegalAccessException,IllegalArgumentException,InvocationTargetException通过反射调用类中的方法12.4.2获取全部方法接下来通过一个案例演示获取类中的方法。1interfaceChina{2publicstaticfinalStringNATION="CHINA";3publicstaticfinalStringAUTHOR="张三";4publicvoidsayChina();5}6classPerson{7privateStringname;8privateintage;9publicPerson(Stringname,intage){10this.setName(name);11this.setAge(age);12}13publicStringgetName(){14returnname;15}
16publicvoidsetName(Stringname){17=name;18}19publicintgetAge(){20returnage;21}22publicvoidsetAge(intage){23this.age=age;24}25publicStringtoString(){26return"姓名:"++",年龄:"+this.age;27}28}12.4.2获取全部方法29classExample06{30publicstaticvoidmain(Stringargs[]){31Class<?>c=null;32try{33c=Class.forName("cn.itcast.Person");34}catch(ClassNotFoundExceptione){35e.printStackTrace();36}37Class<?>cons[]=c.getInterfaces();38for(inti=0;i<cons.length;i++){39System.out.println("实现的接口名称:"+cons[i].getName());40}41}42}12.4.2获取全部方法上述代码中,第1~5行代码首先定义了一个China接口,并在China接口中定义了两个final修饰的String属性和sayChina()方法。第6~28行代码定义了一个Person类。最后在30~41行的main()方法中定义了一个Class的对象,通过Class对象调用forName()方法获取了“cn.itcast.Person”的所有方法。并定义了一个名称为cons[]的Class集合,用于存储Class的所有接口,最后使用for循还打印consp[]集合。从运行结果可以发现,程序不仅将Person类的方法输出,也把从Object类中继承而来的方法同样进行了输出。12.4.2获取全部方法程序运行结果如下图。12.4.3获取全部属性在反射操作中也可以获取一个类中的全部属性,但是类中的属性包括两部分,从父类继承的属性,本类定义的属性。因此,在获取类的属性时也有两种不同的方式,分别如下:(1)获取实现的接口或父类中的公共属性:publicField[]getFieldsthrowsSecurityException。(2)获取本类中的全部属性:publicField[]getDeclaredFieldsthrowsSecurityException。12.4.3获取全部属性上述两种方法返回的都是Field数组,每一个Field对象表示类中的一个属性。如果要获取属性的详细信息,就需要调用Field类的方法。Field类的常用方法如下表。方法描述publicintgetModifiers()得到本方法的修饰符publicStringgetName()得到方法的名称publicbooleanisAccessible()判断此属性是否可被外部访问publicvoidsetAccessible(Booleanflag)throwsSecurityException设置一个属性是否可被外部访问publicStringtoString()返回此Filed类的信息publicObjectget(Objectobj)throwsIllegalArgumentException,IllegalAccessException得到一个对象中属性的具体内容publicvoidset(Objectobj,Objectvalue)throwsIllegalArgumentException,IllegalAccessException设置指定对象中属性的具体内容12.4.3获取全部属性接下来通过一个案例讲解如何获取一个类中的全部属性信息。1importjava.lang.reflect.Field;2importjava.lang.reflect.Modifier;3classPerson{4privateStringname;5privateintage;6publicPerson(Stringname,intage){7this.setName(name);8this.setAge(age);9}10publicStringgetName(){11returnname;12}
13publicvoidsetName(Stringname){14=name;15}16publicintgetAge(){17returnage;18}19publicvoidsetAge(intage){20this.age=age;21}22publicStringtoString(){23return"姓名:"++",年龄:"+this.age;24}25}12.4.3获取全部属性26publicclassExample07{27publicstaticvoidmain(String[]args){28Class<?>c1=null;29try{30c1=Class.forName("cn.itcast.Person");31}catch(ClassNotFoundExceptione){32e.printStackTrace();33}34{35Fieldf[]=c1.getDeclaredFields();//取得本类属性36for(inti=0;i<f.length;i++){//循环输出37Class<?>r=f[i].getType();//取得属性的类型12.4.3获取全部属性38intmo=f[i].getModifiers();//得到修饰符数字39Stringpriv=Modifier.toString(mo);//取得属性的修饰符40System.out.print("本类属性:");41
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《机械制图》-3.2-4 切槽半球
- 安全工器具和防护用品管理制度培训
- 责任两情协议书
- 货款追债协议书
- 货运损坏理赔协议书
- 106机巷东段安全技术措施培训
- 防灾减灾居安思危-2026年中小学全国防灾减灾日主题班会课件
- 陶瓷雕塑项目可行性研究报告
- 骨髓坏死护理查房
- 光电距离传感器项目可行性研究报告
- 2025年水务公司笔试题及答案
- 四川省宜宾市普通高中2023级高考适应性演练(宜宾三诊)地理+答案
- 2026江西省福利彩票发行中心及市级销售机构招聘编外人员14人备考题库及1套完整答案详解
- 《25 黄帝的传说》公开课一等奖创新教学设计及反思
- 2024年中铁施工劳务分包合同示范文本
- 芳纶纤维行业发展趋势分析报告
- 药物警戒管理体系记录与数据管理规程
- E临床医学专业内科学呼吸系统试题
- 教导主任业务知识讲座
- 人教版高中物理新教材同步讲义选修第三册 第2章 2 第1课时 封闭气体压强的计算(含解析)
- 铁路救援起复索具使用指南
评论
0/150
提交评论