1. 定义
在程序运行过程中,可以获取某一个类的成员变量和方法或是构造新的对象,或是可以获取其父类信息,我们称之为反射。
2. jvm如何加载类
- 将java文件编译为class文件
- 根据路径查找到class文件,将class文件使用类加载器(其中用到了反射)加载到内存中
- 验证class文件的准确性
- 为静态变量分配内存空间
- 将内存中的符号引用变为直接引用
- 初始化静态变量和静态代码块
3. 反射的使用
3.1 获取class对象的3种方式
- Class.forName
- 类名.class
- 对象.getClass()
注意:基础数据类型用包装类型.type
package com.liu.reflect;
public class People {
public String sex;
private String height;
}
package com.liu.reflect;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User extends People{
String name;
int age;
private User(String password){
this.password = password;
}
public static void main(String[] args) {
try {
//1.Class.forName
Class<?> aClass1 = Class.forName("com.liu.reflect.User");
//2.类名.class
Class<User> aClass2 = User.class;
//3.对象.getClass()
User user = new User();
Class<? extends User> aClass3 = user.getClass();
System.out.println(aClass1);
System.out.println(aClass2);
System.out.println(aClass3);
//基础数据类型用包装类型.type
System.out.println(Integer.class);
System.out.println(Integer.TYPE);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
3.2 class对象常用方法
getFields()和getMethods()方法获得权限为public成员变量和成员方法时,还包括从父类继承得到的成员变量和成员方法;
getDeclaredFields()和getDeclaredMethods()方法只是获得在本类中定义的所有成员变量和成员方法。
getConstructors():返回当前类的所有public构造
getDeclaredConstructors():返回当前类的所有构造,包含私有
注意:没有任何修饰符时,默认为default修饰
//反射获取类的属性
System.out.println(Arrays.toString(aClass1.getFields()));
System.out.println(Arrays.toString(aClass1.getDeclaredFields()));
//反射获取类的方法
System.out.println(Arrays.toString(aClass1.getMethods()));
System.out.println(Arrays.toString(aClass1.getDeclaredMethods()));
//反射获取构造
//当前类的所有public构造
System.out.println(Arrays.toString(aClass1.getConstructors()));
//当前类的所有构造,包括私有的
System.out.println(Arrays.toString(aClass1.getDeclaredConstructors()));
3.4 暴力破解private
核心都是获取到这个私有的变量或方法,为其添加setAccessible(true)
//私有属性
try {
User user1 = new User("123");
System.out.println("原密码:"+user1.getPassword());
Field password1 = aClass1.getDeclaredField("password");
password1.setAccessible(true);
password1.set(user1,"222");
System.out.println("新密码:"+user1.getPassword());
} catch (Exception e) {
throw new RuntimeException(e);
}
//私有方法
User user1 = new User();
user1.setPassword("111");
System.out.println(user1.password);
Method getPasswordAndName = aClass1.getDeclaredMethod("getPasswordAndName",String.class);
getPasswordAndName.setAccessible(true);
getPasswordAndName.invoke(user1, "222");
System.out.println(user1.password);
3.3 运行结果
class com.liu.reflect.User
class com.liu.reflect.User
class com.liu.reflect.User
class java.lang.Integer
int
[public java.lang.String com.liu.reflect.User.name, public int com.liu.reflect.User.age, public java.lang.String com.liu.reflect.People.sex]
[public java.lang.String com.liu.reflect.User.name, public int com.liu.reflect.User.age, private java.lang.String com.liu.reflect.User.password]
[public static void com.liu.reflect.User.main(java.lang.String[]), public boolean com.liu.reflect.User.equals(java.lang.Object), public java.lang.String com.liu.reflect.User.toString(), public int com.liu.reflect.User.hashCode(), public java.lang.String com.liu.reflect.User.getName(), public void com.liu.reflect.User.setName(java.lang.String), public java.lang.String com.liu.reflect.User.getPassword(), public int com.liu.reflect.User.getAge(), public void com.liu.reflect.User.setAge(int), public void com.liu.reflect.User.setPassword(java.lang.String), public java.lang.String com.liu.reflect.People.getHeight(), public java.lang.String com.liu.reflect.People.getSex(), public void com.liu.reflect.People.setSex(java.lang.String), public void com.liu.reflect.People.setHeight(java.lang.String), public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]
[public static void com.liu.reflect.User.main(java.lang.String[]), public boolean com.liu.reflect.User.equals(java.lang.Object), public java.lang.String com.liu.reflect.User.toString(), public int com.liu.reflect.User.hashCode(), public java.lang.String com.liu.reflect.User.getName(), public void com.liu.reflect.User.setName(java.lang.String), public java.lang.String com.liu.reflect.User.getPassword(), public int com.liu.reflect.User.getAge(), protected boolean com.liu.reflect.User.canEqual(java.lang.Object), public void com.liu.reflect.User.setAge(int), public void com.liu.reflect.User.setPassword(java.lang.String)]
[public com.liu.reflect.User(), public com.liu.reflect.User(java.lang.String,int,java.lang.String)]
[public com.liu.reflect.User(), public com.liu.reflect.User(java.lang.String,int,java.lang.String), private com.liu.reflect.User(java.lang.String)]
原密码:123
新密码:222
111
222
3.4 反射的应用
类加载器:使用反射获取要加载的类
springAOP:使用反射实现动态代理
spring框架:使用反射获取注解标识的方法或属性
数据库连接:使用反射获取驱动