JavaWeb学习大纲传送门
本章学习目录
- 问题的引出:我们如何动态的调用类,从而实现工具类的多用性或者说是通用性呢?
- 问题的解决:Java的反射机制能有效地实现
- 页内目录
一,Java反射机制的基本介绍
二,Java反射机制的基本功能
三,Java反射机制的原理
四,Java反射机制的实用操作
五,Java反射机制的意义
六,Java反射机制的弊端
一,Java反射机制的基本介绍
- Java的反射机制(reflection):是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
- 尽管Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection 这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。大概意思就是,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力被称为introspection(内省、内观、反省)。Reflection和introspection是经常被并提的两个术语。
二,Java反射机制的基本功能
- 主要提供了以下重要功能:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;生成动态代理。
三,Java反射机制的原理
- 反射机制的原理:对于一个字节码文件**.class**,虽然我们对该字节码文件一无所知,但该文件本身却记录了许多信息。Java在将.class字节码文件载入时,JVM将产生一个java.lang.Class对象代表该 .class 字节码文件,从该Class对象中可以获得类的许多基本信息,这就是反射机制。
- 反射机制所需的类主要有java.lang包中的Class类和java.lang.reflect包
- 要使用反射必须先拿到一个类或一个类的的Class对象
Class类:在反射中有一个核心类java.lang.Class类,该类表示的是类或接口的字节码对象. - 在反射包java.lang.reflect中都有相对应的类:
- Field类:对应类中的属性
方法:- 根据属性名获得一个属性对象:
字节码对象.getDeclaredField("属性名");
- 获取本类全部属性:
字节码对象.getDeclaredFields();
- 根据属性名获取本类及父类中public修饰的属性:
字节码对象.getField(“属性名”);
- 获取本类及父类中public修饰的全部属性:
字节码对象.getFields();
- 得到方法返回的属性对象可以调用获得属性类型方法:
属性对象.getType()
- 得到方法返回的属性对象可以调用获得修饰符类型代号方法:
属性对象.getModifiers();
- 得到方法返回的属性对象可以调用获得修饰符类型方法:
Modifier.toString(属性对象.getModifiers());
- 得到方法返回的属性对象可以调用获得属性名方法:
属性对象.getName();
- 根据属性名获得一个属性对象:
- Method类:对应类中的方法
方法:- 根据方法名和参数列表获得一个方法:
字节码对象.getDeclaredMethod("",基本类型.class);
- 获得本类的所有方法:
字节码对象.getDeclaredMethods();
- 本类与父类的方法获得同
field
- 调用类中的方法(对于根据方法名和参数列表获得一个方法):
根据方法名和参数列表获得一个方法的对象.invoke(该字节码对象的实例,为参数赋的值);
- 根据方法名和参数列表获得一个方法:
- Modifier类:对应类中的修饰符
方法:- 无非就是获得对象的数字类型:
获得的对象.getModifiers()
- 转化为真正的修饰符:
Modifier.toString(获得的对象.getModifiers());
- 无非就是获得对象的数字类型:
- Constructor类:对应类中的构造器
方法:- 获得某一个构造方法:
userClass.getDeclaredConstructors(基本类型.class);
- 获得所有构造方法:
userClass.getDeclaredConstructors();
- 获得某一个构造方法:
- 就害怕你说方法知道了,怎么确定返回的是什么呢!
- 根据方法查看:
- 快捷键生成,点击该部分任意一处使用快捷键alt+enter, 就生成了它的返回值类型和
- 根据方法查看:
- Field类:对应类中的属性
四,Java反射机制的实用操作
- 获得一个类的Class对象(字节码对象)和创建对象(含有参)的方式:
java"> //1,根据类的完整路径获取字节码对象
Class userCla1=Class.forName("com.jazhong.reflect.User");
//2,通过类名获取类的字节码文件
Class userCla2=User.class;
//3,通过对象名获取该对象的所对应的字节码文件
User user=new User();
Class userCla3 = user.getClass();
//创建对象 jdk高版本用userCla.getDeclatedConstructor().newInstance();
Object obj = userCla.newInstance();
//有参先要获得有参的构造器然后创建
//获得有参数的构造器
Constructor constructor = userClass.getDeclaredConstructor(int.class, String.class, String.class);
//利用获得的构造方法对象来创建类的对象
Object obj1 = constructor.newInstance(1, "xiaohua", "123456");
- 使用反射操作类中的属性,获得类中的所有属性
java"> //获得字节码对象
Class userClass = User.class;
//获得类中的所有属性
Field[] declaredFields = userClass.getDeclaredFields();
//使用循环遍历,并获得每个属性的详情
for (Field field:declaredFields){
//获得属性名
String name = field.getName();
//获得属性的类型
Class type = field.getType();
//获得属性的修饰符,修饰符modifiersnum得到的是数字
int modifiersnum = field.getModifiers();
//运用Modifier.toString方法转换成修饰符
String modifiers = Modifier.toString(modifiersnum);
System.out.println("属性的修饰符代号"+modifiersnum+"属性的修饰符"+modifiers+"属性的类型"+type+"属性名"+name);
}
- 获得指定的属性并调用该属性为该属性赋值及获取值
java"> //获取User类的字节码文件
Class userCla= User.class;
//根据属性名获取一个属性对象Field
Field field=userCla.getDeclaredField("username");
//创建类的对象
//userCla.newInstance();不能用的,因为你的jdk版本高,所以说可以写成新版的写:userCla.getDeclatedConstructor().newInstance();
Object obj=userCla.newInstance();
//调用属性 参1:对象(调用的对象的属性)
// 参2:值(为属性要设置的值)
field.set(obj,"admin");//等同于 obj.field="admin"
System.out.println((String) field.get(obj));
- 获得类中的方法细节
java"> //获得user类的字节码对象
Class userClass = User.class;
//获得userCla的所有方法
Method[] Methods = userClass.getDeclaredMethods();
//遍历methods
for (Method method:Methods){
//获得方法修饰符
int modifiers = method.getModifiers();
String modifierStr = Modifier.toString(modifiers);
//获得方法返回类型
Class returnType = method.getReturnType();
//获得方法名
String methodName = method.getName();
//获得参数列表
Class[] parameterTypes = method.getParameterTypes();
//获得方法抛出的异常类型
Class[] exceptionTypes = method.getExceptionTypes();
//获得方法的所有注解
Annotation[] annotations = method.getDeclaredAnnotations();
System.out.println(modifierStr+" "+returnType+" "+methodName);
System.out.println("参数列表:");
for(Class paramClass :parameterTypes){
System.out.println(paramClass);
}
System.out.println("异常列表:");
for(Class exType : exceptionTypes){
System.out.println(exType);
}
System.out.println("注解列表:");
for(Annotation annotation :annotations ){
System.out.println(annotation);
}
System.out.println("***************");
}
- 根据方法名和方法的参数列表获得一个方法对象,并调用该方法
java"> //获得user类的字节码对象
Class userCla= User.class;
//根据方法名和参数列表获得一个方法对象
Method method=userCla.getDeclaredMethod("setUsername",String.class);
//创建对象 jdk高版本用userCla.getDeclatedConstructor().newInstance();
Object obj = userCla.newInstance();
//调用方法setUsername,为参数String赋值-笑傲-
method.invoke(obj,"笑傲");//等同于obj.method(")
//获得get方法
Method getmethod=userCla.getDeclaredMethod("getUsername");
//调用方法,返回结果
Object obj1 = getmethod.invoke(obj);
System.out.println(obj1);
- 使用反射获得类中的构造方法
java"> //创建class对象
Class<User> userClass = User.class;
//获得类中的所有构造方法
java.lang.reflect.Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
//遍历数组,获得每个构造器的详情
for (Constructor constructor:declaredConstructors){
//获得构造器方法的名字
String name = constructor.getName();
//获得构造方法的修饰符
String modiferName = Modifier.toString(constructor.getModifiers());
//获得参数列表
Class[] parames = constructor.getParameterTypes();
System.out.println(modiferName+""+name);
//遍历参数列表
for (Class param:parames){
System.out.println(param);
}
}
- 根据参数列表获得指定的构造器并利用该构造器创建对象
java"> Class userClass = User.class;
//使用无参数的构造方法创建类的对象(即userClass对应的类的对象)
//通过class对象调用无参构造方法创建对象
//jdk新版本用userClass.getDeclatedConstructor().newInstance();
Object obj = userClass.newInstance();
//获得有参数的构造器
Constructor constructor = userClass.getDeclaredConstructor(int.class, String.class, String.class);
//利用获得的构造方法对象来创建类的对象
Object obj1 = constructor.newInstance(1, "xiaohua", "123456");
System.out.println(obj1);
五,Java反射机制的意义
- 意义
- 总结:正是反射有以上的特征,所以它能动态编译和创建对象,极大的激发了编程语言的灵活性,强化了多态的特性,进一步提升了面向对象编程的抽象能力,因而受到编程界的青睐。
六,Java反射机制的特性
- 反射机制带来了极大的灵活性及方便性,但反射也有缺点。反射机制的功能非常强大,但不能滥用。在能不使用反射完成的情况下,尽量不使用,原因:
- 性能问题:
Java反射机制中包含了一些动态类型,所以Java虚拟机不能够对这些动态代码进行优化。因此,反射操作的效率要比正常操作效率低很多。我们应该避免在对性能要求很高的程序或经常被执行的代码中使用反射。而且,如何使用反射决定了性能的高低。如果它作为程序中较少运行的部分,性能将不会成为一个问题。 - 安全限制:
使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。 - 程序健壮性:
反射允许代码执行一些通常不被允许的操作,所以使用反射有可能会导致意想不到的后果。反射代码破坏了Java程序结构的抽象性,所以当程序运行的平台发生变化的时候,由于抽象的逻辑结构不能被识别,代码产生的效果与之前会产生差异。
- 性能问题:
注:本片文章对于百度文库中的反射讲解和所学进行的总结