目录
反射机制介绍
什么是反射
反射的作用
创建对象过程
Java创建对象的三个阶段
创建对象时内存结构
反射的具体实现
创建Users类
通过getClass()方法获取Class对象
通过.class 静态属性获取Class对象
通过forName()获取Class对象
获取类的构造方法
通过构造方法创建对象
获取类的成员变量
方法介绍
方法使用
获取成员变量
操作成员变量
获取类的方法
方法介绍
方法使用
获取方法
调用方法
获取类的其他信息
反射应用案例
反射机制的效率
反射机制的效率测试
setAccessible方法
本章总结
反射机制介绍
什么是反射
Java 反射机制是Java语言一个很重要的特性,它使得Java具有了“动 态性”。在Java程序运行时,对于任意的一个类,我们能不能知道这 个类有哪些属性和方法呢?对于任意的一个对象,我们又能不能调 用它任意的方法?答案是肯定的!这种动态获取类的信息以及动态 调用对象方法的功能就来自于Java 语言的反射(Reflection)机 制。
反射的作用
简单来说两个作用,RTTI(运行时类型识别)和DC(动态创建)。 我们知道反射机制允许程序在运行时取得任何一个已知名称的class 的内部信息,包括其modifiers(修饰符),fields(属性),methods(方 法)等,并可于运行时改变fields内容或调用methods。那么我们便 可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间 进行源代码链接,降低代码的耦合度;还有动态代理的实现等等; 但是需要注意的是反射使用不当会造成很高的资源消耗!
创建对象过程
Java创建对象的三个阶段
创建对象时内存结构
Users user = new Users();
实际上,我们在加载任何一个类时都会在方法区中建立“这个类对应 的Class对象”,由于“Class对象”包含了这个类的整个结构信息,所 以我们可以通过这个“Class对象”来操作这个类。 我们要使用一个类,首先要加载类;加载完类之后,在堆内存中, 就产生了一个 Class 类型的对象(一个类只有一个 Class 对象), 这个对象就包含了完整的类的结构信息。我们可以通过这个对象知 道类的结构。这个对象就像一面镜子,透过这个镜子可以看到类的 结构,所以,我们形象的称之为:反射。 因此,“Class对象”是反射 机制的核心。
反射的具体实现
获取Class对象的三种方式
1、通过getClass()方法;
2、通过.class 静态属性;
3、通过Class类中的静态方法forName();
创建Users类
public class Users {
private String username;
private int userage;
public String getUsername() {
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public int getUserage() {
return userage;
}
public void setUserage(int userage) {
this.userage = userage;
}
}
通过getClass()方法获取Class对象
* 通过getClass()方法获取该类的Class对象
*/
public class GetClass1 {
public static void main(String[] args) {
Users users = new Users();
Users users1 = new Users();
Class clazz = users.getClass();
System.out.println(clazz);
System.out.println(clazz.getName());
System.out.println(users.getClass() == users1.getClass());
}
}
通过.class 静态属性获取Class对象
/**
* .class静态属性获取Class对象
*/
public class GetClass2 {
public static void main(String[] args) {
Class clazz = Users.class;
Class clazz2 = Users.class;
System.out.println(clazz);
System.out.println(clazz.getName());
System.out.println(clazz == clazz2);
}
}
通过forName()获取Class对象
/**
* 通过Class.forName("class Name")获取Class对象
*/
public class GetClass3 {
public static void main(String[] args)throws Exception {
Class clazz = Class.forName("com.bjsxt.Users");
Class clazz2 = Class.forName("com.bjsxt.Users");
System.out.println(clazz);
System.out.println(clazz.getName());
System.out.println(clazz == clazz2);
}
}
获取类的构造方法
方法介绍
方法使用
修改Users类
public class Users {
private String username;
private int userage;
public Users(){}
public Users(String username,int userage){
this.username= username;
this.userage=userage;
}
public Users(String username){
this.username= username;
}
private Users(int userage){
this.userage = userage;
}
public String getUsername() {
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public int getUserage() {
return userage;
}
public void setUserage(int userage) {
this.userage = userage;
}
}
获取构造方法
public class GetConstructor {
public static void main(String[] args)throws Exception {
Class clazz = Users.class;
Constructor[] arr = clazz.getDeclaredConstructors();
for(Constructor c:arr){
System.out.println(c);
}
System.out.println("---------------------");
Constructor[] arr1 = clazz.getConstructors();
for(Constructor c:arr1){
System.out.println(c);
}
System.out.println("------------------------");
Constructor c = clazz.getDeclaredConstructor(int.class);
System.out.println(c);
System.out.println("------------------------");
Constructor c1 = clazz.getConstructor(null);
System.out.println(c1);
}
}
通过构造方法创建对象
public class GetConstructor2 {
public static void main(String[] args)throws Exception {
Class clazz = Users.class;
Constructor constructor = clazz.getConstructor(String.class,int.class);
Object o = constructor.newInstance("OldLu",18);
Users users = (Users)o;
System.out.println(users.getUsername()+"\t"+ users.getUserage());
}
}
获取类的成员变量
方法介绍
方法使用
修改Users类
public class Users {
private String username;
public int userage;
public Users(){
}
public Users(String username,int userage){
this.username= username;
this.userage=userage;
}
public Users(String username){
this.username= username;
}
private Users(int userage){
this.userage = userage;
}
public String getUsername() {
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public int getUserage() {
return userage;
}
public void setUserage(int userage) {
this.userage = userage;
}
}
获取成员变量
public class GetField {
public static void main(String[] args)throws Exception {
Class clazz = Users.class;
Field[] fields = clazz.getFields();
for(Field f:fields){
System.out.println(f);
System.out.println(f.getName());
}
System.out.println("------------------------");
Field[] fields2 =clazz.getDeclaredFields();
for(Field f:fields2){
System.out.println(f);
System.out.println(f.getName());
}
System.out.println("------------------------");
Field field = clazz.getField("userage");
System.out.println(field);
System.out.println("---------------------");
Field field1 = clazz.getDeclaredField("username");
System.out.println(field1);
}
}
操作成员变量
public class GetField2 {
public static void main(String[] args)throws Exception {
Class clazz = Users.class;
Field field = clazz.getField("userage");
//对象实例化
Object obj = clazz.newInstance();
//为成员变量赋予新的值
field.set(obj,18);
//获取成员变量的值
Object o = field.get(obj);
System.out.println(o);
}
}
获取类的方法
方法介绍
方法使用
修改Users类
public class Users {
private String username;
public int userage;
public Users(){ }
public Users(String username,int userage){
this.username= username;
this.userage=userage;
}
public Users(String username){
this.username= username;
}
private Users(int userage){
this.userage = userage;
}
public String getUsername() {
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public int getUserage() {
return userage;
}
public void setUserage(int userage) {
this.userage = userage;
}
private void suibian(){
System.out.println("Hello Oldlu");
}
}
获取方法
public class GetMethod {
public static void main(String[] args)throws Exception{
Class clazz = Users.class;
Method[] methods = clazz.getMethods();
for(Method m: methods){
System.out.println(m);
System.out.println(m.getName());
}
System.out.println("---------------------------");
Method[] methods2 = clazz.getDeclaredMethods();
for(Method m: methods2){
System.out.println(m);
System.out.println(m.getName());
}
System.out.println("--------------------------");
Method method = clazz.getMethod("setUserage", int.class);
System.out.println(method.getName());
System.out.println("--------------------------");
Method method1 = clazz.getDeclaredMethod("suibian");
System.out.println(method1.getName());
}
}
调用方法
public class GetMethod2 {
public static void main(String[] args)throws Exception {
Class clazz = Users.class;
Method method = clazz.getMethod("setUsername",String.class);
//实例化对象
Object obj = clazz.getConstructor(null).newInstance();
//通过setUserName赋值
method.invoke(obj,"oldlu");
//通过getUserName获取值
Method method1 = clazz.getMethod("getUsername");
Object value = method1.invoke(obj);
System.out.println(value);
}
}
获取类的其他信息
public class GetClassInfo {
public static void main(String[] args) {
Class clazz = Users.class;
//获取类名
String className = clazz.getName();
System.out.println(className);
//获取包名
Package p = clazz.getPackage();
System.out.println(p.getName());
//获取超类
Class superClass = clazz.getSuperclass();
System.out.println(superClass.getName());
//获取该类实现的所有接口
Class[] interfaces = clazz.getInterfaces();
for(Class inter:interfaces){
System.out.println(inter.getName());
}
}
}
反射应用案例
需求:根据给定的方法名顺序来决定方法的执行顺序。
class Reflect {
public void method1(){
System.out.println("Method1.......");
}
public void method2(){
System.out.println("Method2.......");
}
public void method3(){
System.out.println("Method3.......");
}
}
public class ReflectDemo {
public static void main(String[] args)throws Exception {
Reflect rd = new Reflect();
if(args != null && args.length > 0){
//获取ReflectDemo的Class对象
Class clazz = rd.getClass();
//通过反射获取ReflectDemo下的所有方法
Method[] methods = clazz.getMethods();
for(String str :args){
for(int i=0;i<methods.length;i++){ if(str.equalsIgnoreCase(methods[i].getName())){
methods[i].invoke(rd);
break;
}
}
}
}else{
rd.method1();
rd.method2();
rd.method3();
}
}
}
反射机制的效率
由于Java反射是要解析字节码,将内存中的对象进行解析,包括了 一些动态类型,而JVM无法对这些代码进行优化。因此,反射操作 的效率要比那些非反射操作低得多! 接下来我们做个简单的测试来直接感受一下反射的效率。
反射机制的效率测试
public class Test{
public static void main(String[] args) {
try {
//反射耗时
Class clazz = Class.forName("com.bjsxt.Users");
Users users = (Users) clazz.getConstructor(null).newInstance();
long reflectStart = System.currentTimeMillis();
Method method = clazz.getMethod("setUsername", String.class);
for(int i=0;i<100000000;i++){
method.invoke(users,"oldlu");
}
long reflectEnd = System.currentTimeMillis();
//非反射方式的耗时
long start = System.currentTimeMillis();
Users u = new Users();
for(int i=0;i<100000000;i++){
u.setUsername("oldlu");
}
long end = System.currentTimeMillis();
System.out.println("反射执行时 间:"+(reflectEnd - reflectStart)); System.out.println("普通方式执行时间:"+(end - start));
} catch (Exception e) {
e.printStackTrace();
}
}
}
setAccessible方法
setAccessible()方法: setAccessible是启用和禁用访问安全检查的开关。值为 true 则指示 反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指 示反射的对象应该实施 Java 语言访问检查;默认值为false。 由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关 闭安全检查就可以达到提升反射速度的目的。
public class Test2 {
public static void main(String[] args)throws Exception {
Users users = new Users();
Class clazz = users.getClass();
Field field = clazz.getDeclaredField("username");
//忽略安全检查
field.setAccessible(true);
field.set(users,"oldlu");
Object object = field.get(users); System.out.println(object);
System.out.println("-----------------------------");
Method method = clazz.getDeclaredMethod("suibian");
method.setAccessible(true);
method.invoke(users);
}
}
本章总结
Java 反射机制是Java语言一个很重要的特性,它使得Java具有了 “动态性”。
反射机制的优点:
1、更灵活。
2、更开放。
反射机制的缺点:
1、降低程序执行的效率。
2、增加代码维护的困难。
获取Class类的对象的三种方式:
1、运用getClass()。
2、运用.class 语法。
3、运用Class.forName()(最常被使用)。
反射机制的常见操作
1、动态加载类、动态获取类的信息(属性、方法、构造器)。
2、动态构造对象。
3、动态调用类和对象的任意方法。
4、动态调用和处理属性。
5、 获取泛型信息。
6、处理注解。