目录
反射是java非常重要的东西 没有反射就没有java 是框架设计的灵魂
反射是java非常重要的东西 没有反射就没有java 是框架设计的灵魂
一、什么是反射?
反射java语言中的一种机制,通过这种机制可以动态的实例化对象 、读写属性 、调用方法
任意一个类 都能够获取这个类的属性和方法 都能够调用这个类的属性和方法
(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))
首先先了解一下Class 文件
二、Class详解
Class对象的由来是将class文件读入内存,并为之创建一个Class对象
图解
众所周知,所有 Java 类均继承了 Object 类,在 Object 类中定义了一个 getClass() 方法,该方法返回同一个类型为 Class 的对象。例如,下面的示例代码:
Class labelCls = label1.getClass(); // label1为 JLabel 类的对象
三、反射机制的优缺点
优点:
- 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
- 与 Java 动态编译相结合,可以实现无比强大的功能。
- 对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点:
- 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
- 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。
反射可访问的常用信息(如下图)
四、反射的使用
例1
1)首先创建一个 Book2 类,在该类中依次声明一个 String、int、float 和 boolean 类型的成员,并设置不同的访问作用域。Book2 类最终的代码如下:
public class Book2 {
String name;
public int id;
private float price;
protected boolean isLoan;
}
2)编写测试类 Test03,在该类的 main() 方法中通过反射访问 Book2 类中的所有成员,并将该成员的名称和类型信息输出到控制台。
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Test03 {
public static void main(String[] args) {
Book2 book = new Book2();
// 获取动态类Book2
Class class1 = book.getClass();
// 获取Book2类的所有成员
Field[] declaredFields = class1.getDeclaredFields();
// 遍历所有的成员
for(int i = 0;i < declaredFields.length;i++) {
// 获取类中的成员变量
Field field = declaredFields[i];
System.out.println("成员名称为:" + field.getName());
Class fieldType = field.getType();
System.out.println("成员类型为:" + fieldType);
boolean isTurn = true;
while(isTurn) {
try {
// 如果该成员变量的访问权限为private,则抛出异常
isTurn = false;
System.out.println("修改前成员的值为:" + field.get(book));
// 判断成员类型是否为int
if(fieldType.equals(int.class)) {
System.out.println("利用setInt()方法修改成员的值");
field.setInt(book, 100);
} else if(fieldType.equals(float.class)) {
// 判断成员变量类型是否为float
System.out.println("利用setFloat()方法修改成员的值");
field.setFloat(book, 29.815f);
} else if(fieldType.equals(boolean.class)) {
// 判断成员变量是否为boolean
System.out.println("利用setBoolean()方法修改成员的值");
field.setBoolean(book, true);
} else {
System.out.println("利用set()方法修改成员的值");
field.set(book, "Java编程");
}
System.out.println("修改后成员的值为:" + field.get(book));
} catch (Exception e) {
System.out.println("在设置成员变量值时抛出异常,下面执行setAccessible()方法");
field.setAccessible(true);
isTurn = true;
}
}
System.out.println("=============================\n");
}
}
}
3)运行测试类 Test03,程序将会依次动态访问 Book2 类中的所有成员。访问 name 成员的运行效果如下所示:
成员名称为:name 成员类型为:class java.lang.String 修改前成员的值为:null 利用set()方法修改成员的值 修改后成员的值为:Java编程
访问 id 成员的运行效果如下所示:
成员名称为:id 成员类型为:int 修改前成员的值为:0 利用setInt()方法修改成员的值 修改后成员的值为:100 =============================
访问 price 成员的运行效果如下所示:
成员名称为:price 成员类型为:float 在设置成员变量值时抛出异常,下面执行setAccessible()方法 修改前成员的值为:0.0 利用setFloat()方法修改成员的值 修改后成员的值为:29.815 =============================
访问 isLoan 成员的运行效果如下所示
成员名称为:isLoan 成员类型为:boolean 修改前成员的值为:false 利用setBoolean()方法修改成员的值 修改后成员的值为:true =============================
getDeclaredMethod (暴力反射)
package com.test;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.function.Predicate;
import javax.servlet.Servlet;
public class Test implements Serializable,Predicate{
@Override
public boolean test(Object t) {
// TODO Auto-generated method stub
return false;
}
//反射
// 就是程序中的X光,当一个类被加载到JVM(java虚拟机)
// 这个类就会变得透明(属性,方法)全部都可以看到,可以调用
// 反射效率低,如果是私有化的方法或者属性可能会报错
//反射的应用:
// jdbc: Class.forName("mysql.driver")
// web.xml: <servlet-class>com.test.xxServlet</servlet-class>
/**
* 获取类对象
* @throws Exception
*/
public void reflectClz() throws Exception {
//所有的反射都从类对象开始
//类对象的获取方式:3
//1.获取当前类的对象
Class<? extends Test> c1 = this.getClass();
//2.通过类名来获取类对象
Class<? extends Test> c2=Test.class;
//3.通过全路径名称来获得类对象
Class<?> c3=(Class<? extends Test>) Class.forName("com.test.Test");
System.out.println("全路径名称"+c3.getName());
System.out.println("类名称"+c3.getSimpleName());
System.out.println("包名称"+c3.getPackage());
//修饰符: public private protected final static
System.out.println("修饰符"+Modifier.toString(c3.getModifiers()));
}
/**
* 通过类对象获取类实例(instance)
* @throws Exception
*/
public void reflectObj() throws Exception {
// Stu stu=new Stu();
//1.通过类对象生产实例 Stu
Class<Stu> c=Stu.class;
//调用方法 newInstance 得到实例
// Stu s = c.newInstance();//调用无参构造
//2.直接获取类上面的构造函数
Constructor<Stu> constructor = c.getConstructor(String.class,int.class);
//基本类型必须使用基本类型的class
Stu s1 = constructor.newInstance("小黑",19);
System.out.println(s1);
/**
Constructor<?>[] constructors = c.getConstructors();
for (Constructor<?> cs : constructors) {
System.out.println(cs);
}
**/
}
/**
* 通过类对象获取属性
* @throws Exception
*/
public void reflectField(Object obj) throws Exception {
Class<? extends Object> clz = obj.getClass();
//获取stu中所有的属性
Field[] fs = clz.getDeclaredFields();
/**
只能取到public
Field[] fields = clz.getFields();
**/
for (Field f : fs) {
System.out.println("属性名"+f.getName());
System.out.println("属性修饰符"+Modifier.toString(f.getModifiers()));
System.out.println("属性类型"+f.getType());
//f.get() 从某个对象中获取该属性
f.setAccessible(true);//当前不进行安全检查
System.out.println(f.get(obj));
}
//修改她的年龄
Field f = clz.getDeclaredField("age");
//set(你要设置的对象,设置什么值)
// obj.age=15
f.setAccessible(true);
f.set(obj, 15);
System.out.println(obj);
}
/**
* 通过类对象获取类方法
* @throws Exception
*/
public void reflectMethod() throws Exception{
Stu s=new Stu("效率",90);
//获取这个类中方法
Class<? extends Stu> clz = s.getClass();
//获得名字 getName
Method m1 = clz.getDeclaredMethod("getName");
//invoke(谁来调用这个方法,参数值) 执行方法
m1.setAccessible(true);
Object obj = m1.invoke(s);
System.out.println(obj);
//设置当前学生的年龄为18 setAge
Method m2 = clz.getDeclaredMethod("setAge",int.class);
Object obj2 = m2.invoke(s, 18);
System.out.println(obj2);
/**
Method[] methods = clz.getDeclaredMethods();
for (Method m : methods) {
System.out.println(m);
System.out.println("方法修饰符"+Modifier.toString(m.getModifiers()));
}
**/
}
/**
* 通过类对象获取上级元素(父类,接口)
* @throws Exception
*/
public void reflectTop() throws Exception{
//单继承 拿父类
Class<?> clz = this.getClass().getSuperclass();
System.out.println(clz);
//多实现 多个接口
Class<?>[] interfaces = this.getClass().getInterfaces();
for (Class<?> c : interfaces) {
System.out.println(c.getName());
}
}