java反射详解
2016-11-18 13:09
399 查看
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:232300090我们一起学Java!
本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解。
下面开始正文。
【案例1】通过一个对象获得完整的包名和类名
【运行结果】:Reflect.Demo
添加一句:所有类的对象其实都是Class的实例。
【案例2】实例化Class类对象
【运行结果】:
类名称Reflect.Demo
类名称Reflect.Demo
类名称Reflect.Demo
【案例3】通过Class实例化其他类的对象
通过无参构造实例化对象
【运行结果】:
[Rollen20]
但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:
比如我定义了一个构造函数:
然后继续运行上面的程序,会出现:
java.lang.InstantiationException:Reflect.Person
atjava.lang.Class.newInstance0(Class.java:340)
atjava.lang.Class.newInstance(Class.java:308)
atReflect.hello.main(hello.java:39)
Exceptioninthread"main"java.lang.NullPointerException
atReflect.hello.main(hello.java:47)
所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数
【案例】通过Class调用其他类中的构造函数(也可以通过这种方式通过Class创建其他类的对象)
【运行结果】:
[null0]
[Rollen0]
[null20]
[Rollen20]
【案例】
返回一个类实现的接口:
【运行结果】:
实现的接口Reflect.China
(注意,以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)
【案例】:取得其他类中的父类
【运行结果】
继承的父类为:java.lang.Object
【案例】:获得其他类中的全部构造函数
这个例子需要在程序开头添加importjava.lang.reflect.*;
然后将主类编写为:
【运行结果】:
构造方法:publicReflect.Person()
构造方法:publicReflect.Person(java.lang.String)
但是细心的读者会发现,上面的构造函数没有public或者private这一类的修饰符
下面这个例子我们就来获取修饰符
【运行结果】:
构造方法:publicReflect.Person(){}
构造方法:publicReflect.Person(java.lang.Stringarg1){}
有时候一个方法可能还有异常,呵呵。下面看看:
【运行结果】:
publicjava.lang.StringgetSex()
publicvoidsetSex(java.lang.Stringarg0)
publicvoidsayChina()
publicvoidsayHello(java.lang.Stringarg0,intarg1)
publicfinalnativevoidwait(longarg0)throwsjava.lang.InterruptedException
publicfinalvoidwait()throwsjava.lang.InterruptedException
publicfinalvoidwait(longarg0,intarg1)throwsjava.lang.InterruptedException
publicbooleanequals(java.lang.Objectarg0)
publicjava.lang.StringtoString()
publicnativeinthashCode()
publicfinalnativejava.lang.ClassgetClass()
publicfinalnativevoidnotify()
publicfinalnativevoidnotifyAll()
【案例】接下来让我们取得其他类的全部属性吧,最后我讲这些整理在一起,也就是通过class取得一个类的全部框架
【运行结果】:
===============本类属性========================
privatejava.lang.Stringsex;
===============实现的接口或者父类的属性========================
publicstaticfinaljava.lang.Stringname;
publicstaticfinalintage;
【案例】其实还可以通过反射调用其他类中的方法:
【运行结果】:
hello,china
Rollen20
【案例】调用其他类的set和get方法
【运行结果】:
男
【案例】通过反射操作属性
【案例】通过反射取得并修改数组的信息:
【运行结果】:
数组类型:int
数组长度5
数组的第一个元素:1
修改之后数组第一个元素为:100
【案例】通过反射修改数组大小
【运行结果】:
数组长度为:15
123456789000000=====================
数组长度为:8
abcnullnullnullnullnull
动态代理
【案例】首先来看看如何获得类加载器:
【程序输出】:
类加载器sun.misc.Launcher$AppClassLoader
其实在java中有三种类类加载器。
1)BootstrapClassLoader此加载器采用c++编写,一般开发中很少见。
2)ExtensionClassLoader用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3)AppClassLoader加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
【运行结果】:
Rollen20
类的生命周期
在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。
类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。但是同一个类只会被类装载器装载以前
链接就是把二进制数据组装为可以运行的状态。
链接分为校验,准备,解析这3个阶段
校验一般用来确认此二进制文件是否适合当前的JVM(版本),
准备就是为静态成员分配内存空间,。并设置默认值
解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)
完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。
当没有任何引用指向Class对象时就会被卸载,结束类的生命周期
将反射用于工厂模式
先来看看,如果不用反射的时候,的工厂模式吧:
/detail/2524658601.html
这样,当我们在添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。
现在我们看看利用反射机制:
现在就算我们添加任意多个子类的时候,工厂类就不需要修改。
上面的爱吗虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。
下面我们来看看:结合属性文件的工厂模式
首先创建一个fruit.properties的资源文件,
内容为:
然后编写主类代码:
【运行结果】:Apple
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:232300090我们一起学Java!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:232300090我们一起学Java!
本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解。
下面开始正文。
【案例1】通过一个对象获得完整的包名和类名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
添加一句:所有类的对象其实都是Class的实例。
【案例2】实例化Class类对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
类名称Reflect.Demo
类名称Reflect.Demo
类名称Reflect.Demo
【案例3】通过Class实例化其他类的对象
通过无参构造实例化对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
[Rollen20]
但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:
比如我定义了一个构造函数:
1 2 3 4 |
java.lang.InstantiationException:Reflect.Person
atjava.lang.Class.newInstance0(Class.java:340)
atjava.lang.Class.newInstance(Class.java:308)
atReflect.hello.main(hello.java:39)
Exceptioninthread"main"java.lang.NullPointerException
atReflect.hello.main(hello.java:47)
所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数
【案例】通过Class调用其他类中的构造函数(也可以通过这种方式通过Class创建其他类的对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
[null0]
[Rollen0]
[null20]
[Rollen20]
【案例】
返回一个类实现的接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
实现的接口Reflect.China
(注意,以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)
【案例】:取得其他类中的父类
1 2 3 4 5 6 7 8 9 10 11 12 13 |
继承的父类为:java.lang.Object
【案例】:获得其他类中的全部构造函数
这个例子需要在程序开头添加importjava.lang.reflect.*;
然后将主类编写为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
构造方法:publicReflect.Person()
构造方法:publicReflect.Person(java.lang.String)
但是细心的读者会发现,上面的构造函数没有public或者private这一类的修饰符
下面这个例子我们就来获取修饰符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
构造方法:publicReflect.Person(){}
构造方法:publicReflect.Person(java.lang.Stringarg1){}
有时候一个方法可能还有异常,呵呵。下面看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
publicjava.lang.StringgetSex()
publicvoidsetSex(java.lang.Stringarg0)
publicvoidsayChina()
publicvoidsayHello(java.lang.Stringarg0,intarg1)
publicfinalnativevoidwait(longarg0)throwsjava.lang.InterruptedException
publicfinalvoidwait()throwsjava.lang.InterruptedException
publicfinalvoidwait(longarg0,intarg1)throwsjava.lang.InterruptedException
publicbooleanequals(java.lang.Objectarg0)
publicjava.lang.StringtoString()
publicnativeinthashCode()
publicfinalnativejava.lang.ClassgetClass()
publicfinalnativevoidnotify()
publicfinalnativevoidnotifyAll()
【案例】接下来让我们取得其他类的全部属性吧,最后我讲这些整理在一起,也就是通过class取得一个类的全部框架
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
===============本类属性========================
privatejava.lang.Stringsex;
===============实现的接口或者父类的属性========================
publicstaticfinaljava.lang.Stringname;
publicstaticfinalintage;
【案例】其实还可以通过反射调用其他类中的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
hello,china
Rollen20
【案例】调用其他类的set和get方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
男
【案例】通过反射操作属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
1 2 3 4 5 6 7 8 9 10 11 12 |
数组类型:int
数组长度5
数组的第一个元素:1
修改之后数组第一个元素为:100
【案例】通过反射修改数组大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
数组长度为:15
123456789000000=====================
数组长度为:8
abcnullnullnullnullnull
动态代理
【案例】首先来看看如何获得类加载器:
1 2 3 4 5 6 7 8 9 |
类加载器sun.misc.Launcher$AppClassLoader
其实在java中有三种类类加载器。
1)BootstrapClassLoader此加载器采用c++编写,一般开发中很少见。
2)ExtensionClassLoader用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3)AppClassLoader加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
Rollen20
类的生命周期
在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。
类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。但是同一个类只会被类装载器装载以前
链接就是把二进制数据组装为可以运行的状态。
链接分为校验,准备,解析这3个阶段
校验一般用来确认此二进制文件是否适合当前的JVM(版本),
准备就是为静态成员分配内存空间,。并设置默认值
解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)
完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。
当没有任何引用指向Class对象时就会被卸载,结束类的生命周期
将反射用于工厂模式
先来看看,如果不用反射的时候,的工厂模式吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
现在我们看看利用反射机制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
上面的爱吗虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。
下面我们来看看:结合属性文件的工厂模式
首先创建一个fruit.properties的资源文件,
内容为:
1 2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:232300090我们一起学Java!
相关文章推荐
- JAVA中的反射机制详解
- JAVA中的反射机制详解
- Java Reflection (JAVA反射) 详解
- JAVA基础--JAVA中的反射机制详解
- JAVA中的反射机制详解
- JAVA中的反射机制详解
- JAVA中的反射机制详解
- JAVA中的反射机制详解
- JAVA的反射机制详解
- JAVA基础--JAVA中的反射机制详解
- JAVA基础--JAVA中的反射机制详解
- Java Reflection (JAVA反射)详解 (二)
- Java Reflection (JAVA反射)详解(一)
- JAVA中的反射机制详解
- JAVA基础--JAVA中的反射机制详解
- Java Reflection (JAVA反射)详解
- Java Reflection (JAVA反射)详解
- Java Reflection (JAVA反射)详解
- 传智播客 Java网络公开课二反射详解
- JAVA中的反射机制详解