黑马程序员--自学笔记--反射
来源:互联网 发布:守望先锋性能数据vrm 编辑:程序博客网 时间:2024/06/05 06:44
反射
-------- android培训、java培训、期待与您交流! ---------
一.概述
Java反射机制是在运行状态中,对于任意一个类(class文件),都能够查询并操作这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
总而言之,反射就是把Java类中的各种成分映射成相应的Java类。比如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分可分为:成员变量,方法,构造方法,包等。这些成分都可以用一个个的Java类来表示。表示java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息用相应的类的实例对象来表示,它们分别是Field,Method,Contructor,Package等等。
二.Class类字节码文件
用于描述字节码的类就是Class类。只要创建Class类对象,就可以提取出字节码文件中的各种内容包括:字段、构造函数、一般函数。反射就是依靠Class类来完成的。如果要想对一个类文件中的内容进行操作,就要先获取到该类的字节码文件对象。 获取Class对象的三种方式:(代码演示)
① 第一种方式:
<strong><span style="font-family:KaiTi_GB2312;"><strong><span style="font-family:KaiTi_GB2312;"><span style="font-family:KaiTi_GB2312;"><strong><strong><span style="font-size:14px;">/* * 1.使用object类的getClass()方法; * (此种方式必须明确具体的类,并创建对象) */private static void getClassObject_1() {Person p1 = new Person() ;Class clazz = p1.getClass() ;System.out.println(clazz);}</span></strong></strong></span></span></strong></span></strong>② 第二种方式:
<strong><span style="font-family:KaiTi_GB2312;"><strong><span style="font-family:KaiTi_GB2312;"><span style="font-family:KaiTi_GB2312;"><strong>/* * 2.通过利用任何数据所具备的一个静态属性.class来获取其对应的class对象 * (此种方式不够扩展,还是需要明确用到类中的静态成员) */private static void getClassObject_2() {Class clazz = Person.class ;System.out.println(clazz);}</strong></span></span></strong></span></strong>③ 第三种方式:
<strong><span style="font-family:KaiTi_GB2312;"><strong><span style="font-family:KaiTi_GB2312;"><span style="font-family:KaiTi_GB2312;"><strong>/* * 3.使用Class类中的forname(String str)方法,通过传入类的名字来获取其对应的class对象 * (传入类名时,需将类的整个包名传入。该方法更为扩展) * */private static void getClassObject_3() throws ClassNotFoundException {String className = "cn.itzixue.bean.Person" ;Class clazz = Class.forName(className) ; // 需要完整的类名System.out.println(clazz);}</strong></span></span></strong></span></strong>相比三种获取方式,第一种方式最不灵活,因为这种方式每次都需要具体的类和该类的对象,以及调用getClass方法;第二种方式虽然比第一种较为简单,不用创建对象,也不用调用getClass方法,但是还是要使用具体的类,和该类中的一个静态属性class完成。而第三种方式最简单,只要知道类的名称即可。这种方式不需要使用该类,也不需要去调用具体的属性和行为就可以获取到Class对象。因为第三种方式仅知道类名就可以获取到该类字节码对象的方式,所以更有利于扩展,开发中最常使用。
编译时刻加载类是静态加载类,运行时刻加载类是动态加载类。其中,使用new创建对象是静态加载类,在编译时可就需要加载所有的可能使用到的类。而动态加载类是在运行时刻进行加载,反射利用最多的就是动态加载类。
三.获取Class中的构造函数
获取构造函数一般使用的是Class类对象的getConstructor()方法来获取(该方法返回一个Constructor类对象)。如果构造方法是需要传入参数的,则在创建对象时要使用Constructor类对象的newInstance()方法;若是空参构造函数,则可以使用Class类中的newInstance()方法。代码演示:
① 调用类的空参构造方法创建一个新的对象(传统方法):(注意:注释中包含重要知识点和注意点)
<strong><span style="font-family:KaiTi_GB2312;"><strong><span style="font-family:KaiTi_GB2312;"><span style="font-family:KaiTi_GB2312;"><strong>/* 通过new来实例化对象,在new的时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,接着创建该字节码文件对象,并接着创建该字节码文件对应的Person对象。*/public static void creatNewObject_1() {Person p1 = new Person() ;}</strong></span></span></strong></span></strong>② 调用类的空参构造方法创建一个新的对象(利用反射机制): (注意:注释中包含重要知识点和注意点)
<strong><span style="font-family:KaiTi_GB2312;"><strong><span style="font-family:KaiTi_GB2312;"><span style="font-family:KaiTi_GB2312;"><strong>/* 先利用Class类的fotName(String str)方法找寻所传入名称的类文件吗,并加载进内存,接着产生Class对象。通过利用Class对象的newInstance()方法来创建所传入类的对象。(该方法扩展性强)*/public static void creatNewObject_2() throws ClassNotFoundException, InstantiationException, IllegalAccessException {String className = "cn.itzixue.bean.Person" ;Class clazz = Class.forName(className) ;Object obj = clazz.newInstance() ;}</strong></span></span></strong></span></strong>③调用类的带参构造方法创建一个新的对象(利用反射机制): (注意:注释中包含重要知识点和注意点)
<strong><span style="font-family:KaiTi_GB2312;"><strong><span style="font-family:KaiTi_GB2312;"><span style="font-family:KaiTi_GB2312;"><strong>/* 先通过Class类对象的getConstructor(Class<?>... parameterType)方法来获取制定大的公共构造方法。(该方法返回一个Constructor对象,若要获取包括私有在内的指定构造方法,使用getDeclaredConstructor(Class<?>... parameterType)方法)。再通过调用所获得的对象的newInstance()方法进行对象初始化。*/public static void creatNewObject_3() throws Exception {String className = "cn.itzixue.bean.Person" ;Class clazz = Class.forName(className) ;//获取指定的构造函数对象Constructor constructor = clazz.getConstructor(String.class,int.class) ;//通过该构造器对象初始化对象(结果返回的是Object对象)Object obj = constructor.newInstance("权权",21) ;}</strong></span></span></strong></span></strong>
通过Class类对象的getConstructors()方法可以获取Class字节码文件中的所有公有的(包括父类)构造函数:getDeclaredConstructors()方法可以获取Class字节码文件中的所有(仅本类但包括私有的)构造函数。
四.获取Class中的字段
获取class字节码文件中的字段一般使用的是Class类对象的getField()方法来获取(该方法返回一个Field类对象)。Class类对象中操作字段的相关方法代码演示:
① (返回值类型:Field) getField(String str) ; // 此方法只能获取本类或者父类中的公有的字段
② (返回值类型:Field) getDeclaredField(String str) ; // 此方法只能获取该类中的字段,但是包括私有
Field类中
① (返回值类型:void) setAccessible(true) ; // 通过此方法,可以让该私有字段进行取消权限检查的能力,以便于更轻松的访问(也称之为暴力访问)
② (返回值类型:void) set(Object obj, Object value) ; // 将指定对象变量上此Field对象所表示的字段设置为指定的新值
③ (返回值类型:void) get(Object obj) ; // 返回指定对象上Field表示的字段的值
代码演示:(注意:注重中包含重要知识点和注意点)
<strong><span style="font-family:KaiTi_GB2312;">public static void getFieldDemo() throws Exception {Class clazz = Class.forName("cn.itzixue.bean.Person") ;//通过Class类的对象的getField("字段名称")方法获取制定类中共有的字段(只能获取共有,可以获取父类)//通过Class类的对象的getDeclaredField("字段名称")方法获取制定类中共有的字段(只能获取本类,但是可以包含私有)Field field = clazz.getDeclaredField("age") ;/*通过获得的字段处理其对应的值例如:获取字段的值,可用字段对象的get(?)方法,所传入的?必须是该字段所在类的对象(如果在类中该字段被定义成私有的,则用该方法会抛出无效访问异常) 对私有字段的访问,可以通过其getAccessible(true)方法对其进行暴力访问(不建议!!!)*/Constructor constructor = clazz.getConstructor(String.class,int.class) ;Object obj = constructor.newInstance("权权",21) ;field.setAccessible(true) ;Object o = field.get(obj) ;System.out.println(o) ;//设置所获得的字段的值field.set(obj, 22);o = field.get(obj) ;System.out.println(o);<span style="font-size:14px;">}</span></span></strong>
通过Class类对象的getField()方法可以获取Class字节码文件中的所有公有的(包括父类)字段;getDeclaredField()方法可以获取Class字节码文件中的所有(仅本类但包括私有的)字段。
五.获取Class中的方法
获取class字节码文件中的方法一般可以通过调用getMethod(String name,Class<?>... parameterTypes)方法,该方法将方法名和其参数同时传入。(如果为空参数,则传入null即可。该方法返回一个Method类对象)。获取class字节码文件中的方法代码演示:
① (返回值类型:Method[]) methods = Class.getMethods() ; // 获取类(包括父类)中所有的公有方法
② (返回值类型:Method[]) methods= Class.getDeclaredMethods() ; // 获取类中所有方法(包括私有但不包括父类)
③ (返回值类型:Method) method = Class.getMethod(String name, 参数类型.Class,…参数类型.Class) ;
// 返回一个带参数的Method对象,它反映此Class对象所表示的类或接口的指定公共方法
对获取到的Method对象进行调用代码演示:
(返回值类型:Object) invoke(Object obj,参数) ;
// 由obj对象进行方法调用,如果该方法是静态的,则invoke方法中的对象参数可以置为null
代码演示: (注意:注重中包含重要知识点和注意点)
① 获取无参方法
<strong><span style="font-family:KaiTi_GB2312;"><span style="font-size: 14px;">public static void getMedthodDemo_1() throws Exception {Class clazz = Class.forName("cn.itzixue.bean.Person") ;//可以通过Class对象的getMethod()方法来获取类中所有公共方法(包括父类)。Method[] method_1 = clazz.getMethods() ;//该方法将返回一个Method数组,可通过foreach遍历for(Method m : method_1){System.out.println(m);}//可以通过Class对象的getDeclaredMethod()方法来获取类中包括私有在内的所有方法(不包括父类)。Method[] method_2 = clazz.getDeclaredMethods() ;//该方法将返回一个Method数组,可通过foreach遍历for(Method m : method_2){System.out.println(m);}</span><span style="font-size:14px;">}</span></span></strong>② 获取有参方法并对其进行调用
<strong><span style="font-family:KaiTi_GB2312;"><span style="font-size:14px;">public static void getMedthodDemo_2() throws Exception {</span>Class clazz = Class.forName("cn.itzixue.bean.Person") ;/*获取类中指定的方法,可以通过调用getMethod(String name,Class<?>... parameterTypes)方法,该方法将方法名和其参数同时传入。(如果为空参数,则传入null即可)*/Method method_1 = clazz.getMethod("show", null) ;Method method_2 = clazz.getMethod("show", String.class) ;System.out.println(method_1);System.out.println(method_2);/*若想调用所取到的Method对象,可以使用Method对象的invoke(Object obj,Object... args)方法,该方法需同时传入该类的对象以及相应的参数。*/Constructor constructor = clazz.getConstructor(String.class,int.class) ;Object obj = constructor.newInstance("权权",24) ; method_1.invoke(obj, null) ;method_2.invoke(obj, "No1") ;}</span></strong>
六.总结
反射机制的灵活性很大,使用反射机制,我们可以极大的提高程序的扩展性。同时,反射机制使用的是动态加载,动态编译的优点是最大限度发挥了java的灵活性,又体现了多态的应用,也可以很大程度上降低类之间的藕合。这种机制,在框架的编写上最常使用到。 0 0
- 黑马程序员--自学笔记--反射
- 黑马程序员---自学随堂笔记----反射
- 黑马程序员——自学笔记8(反射)
- 黑马程序员java自学总结之--反射
- 黑马程序员_java基础自学反射
- 黑马程序员--自学笔记--多线程
- 黑马程序员--自学笔记--异常
- 黑马程序员---反射学习笔记
- 黑马程序员 反射学习笔记
- 黑马程序员-java反射笔记
- 黑马程序员_java反射笔记
- 黑马程序员—反射笔记
- 黑马程序员---反射学习笔记
- 【黑马程序员】Java笔记--反射
- 黑马程序员-反射学习笔记
- 黑马程序员----反射学习笔记
- 黑马程序员----C#基础自学笔记
- 黑马程序员----C#面向对象自学笔记
- Linux常用快捷键
- Objective-C 中声明指针变量时 星号( *)如何安放 居左or居右
- confluence数据备份与还原
- eredis连接twemproxy auth失败的问题
- sql内置函数pivot强大的行转列功能
- 黑马程序员--自学笔记--反射
- python--自动删除文件
- 利用scp 远程上传下载文件/文件夹
- TextView 添加链接
- 文章标题
- DEELX 正则表达式扩展语法:递归表达式
- 时间都去哪了
- ping命令是什么协议?
- 关于Android生命周期方法调用return的问题