初始反射
反射是指在Java运行状态中
- 给定一个类对象(Class对象),通过反射获取这个类对象(Class对象)的所有成员结构;
- 给定一个具体的对象,能够动态地调用它的方法及对任意属性值进行获取和赋值
这种动态获取类的内容、创建对象、以及动态调用对象方法及操作属性的机制,就叫做Java的反射机制
https://docs.oracle.com/javase/8/docs/api/
优缺点:
优
- 增加程序的灵活性,避免将固有的逻辑程序写死到代码里
- 代码简洁,可读性强,可提高代码的复用率
缺点 - 相较直接调用在创建对象比较多的情景下反射性能下降
- 内部暴露和安全隐患(破坏单例)
反射性能慢原因
- 寻找类Class字节码的过程,比如通过ClassName找到对应的字节码Class,然后进行加载、解析,也会比较慢,而new的方式则无需寻找,因为在Linking的解析阶段已经将符号引用转为了直接引用
- 安全管理机制的权限验证等等
- 若需要调用native方法调用时JNI接口的使用
- 入参校验
jdk底层源码查看:http://hg.openjdk.java.net/ 选择具体版本查看jdk和hotspot源码
反射的基本操作
Class对象的组成
获取Class对象的四种方式
- 通过ClassLoader对象的loadClass()方法
- 类名.class
- Class.forName() // 会初始化
- object.getClass() // 会初始化
Person类:
import java.lang.reflect.Method;
public class Person {
static {
System.out.println("初始化...");
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void study() {
System.out.println("good good study day day up。。。");
}
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<Person> clazz = Person.class;
// 获得类的结构
System.out.println(clazz.getSuperclass());
System.out.println(clazz.getClassLoader());
System.out.println(clazz.getPackage());
System.out.println(clazz.getName());
// 动态创建对象
Person person = clazz.newInstance();
// 调用方法
Method studyMethod = clazz.getDeclaredMethod("study");
studyMethod.invoke(person);
}
}
public class CoreMain {
public static void main(String[] args) throws Exception {
// 1、类名.class方式,该方式不会对类进行初始化操作
Class<Person> clazz01 = Person.class;
System.out.println(clazz01);
// 2、Class.forName,该方式会进行类的初始化操作,例如MySQL驱动加载
Class<?> clazz02 = Class.forName("com.jw.javacore.reflection.pojo.Person");
System.out.println(clazz02);
// 3、对象.getClass(),会初始化
Class<? extends Person> clazz03 = new Person().getClass();
System.out.println(clazz03);
// 4、通过类加载器.loadClass(),不会初始化
Class<?> clazz04 = CoreMain.class.getClassLoader().loadClass("com.jw.javacore.reflection.pojo.Person");
System.out.println(clazz04);
}
}
基本信息操作
int modifier = clazz.getModifiers(); // 获取类修饰符
Package aPackage = clazz.getPackage(); // 获取类包名
String fullClassName = clazz.getName(); // 获取类的全路径名称
String simpleName = clazz.getSimpleName(); // 获取类的简单名称
ClassLoader classLoader = clazz.getClassLoader(); // 获取类加载器
Class[] interfaces = clazz.getInterfaces(); // 获取类实现的接口列表
Class superclass = clazz.getSuperclass(); // 获取类的父类
Annotation[] annotations = clazz.getAnnotations(); // 获取类的注解信息
@Test
public void testBasicOperate() throws Exception {
Class<Person> clazz01 = Person.class;
System.out.println(clazz01);
// 通过Clazz获取基本信息;属性信息;方法信息;注解信息
System.out.println("--------------");
int modifiers = clazz01.getModifiers();// 获取的是类的修饰符
System.out.println(modifiers);
System.out.println(clazz01.getPackage());
System.out.println(clazz01.getName());
System.out.println(clazz01.getSimpleName());
System.out.println(clazz01.getClassLoader());
System.out.println(clazz01.getInterfaces());
System.out.println(clazz01.getSuperclass());
System.out.println(clazz01.getAnnotations());
}
类的属性操作示例
@Test
public void testFields() throws Exception {
Class<User> clazz = User.class;
User user = clazz.newInstance();// 反射调用的无参的构造方法
System.out.println("--------------");
Field[] fields = clazz.getFields();// 所有public字段、包括继承来的
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("--------------");
Field[] declaredFields = clazz.getDeclaredFields();// 获取当前类中定义的字段
for (Field field : declaredFields) {
System.out.println(field.getName());
}
System.out.println("--------------");
Field addressField = clazz.getDeclaredField("address");// 获取指定名称的类中定义的字段
int modifiers = addressField.getModifiers();// 获取字段的修饰符
addressField.setAccessible(true); // 设置字段的强制访问
addressField.set(user, "极北之地");// 修改字段你的值
System.out.println(user.getAddress());
Field nationalityField = clazz.getDeclaredField("nationality");
nationalityField.set(null, "光明帝国");// 静态字段赋值
System.out.println(user.nationality);
}
类的方法操作
@Test
public void testMethods() throws Exception {
Class<User> clazz = User.class;
User user = clazz.newInstance();// 反射调用的无参的构造方法
System.out.println("--------------");
Method[] methods = clazz.getMethods();// 获取所有的public方法、包括继承来的
for (Method method : methods) {
System.out.println(method);
}
System.out.println("--------------");
Method[] declaredMethods = clazz.getDeclaredMethods();// 获取类中定义的方法
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("--------------");
Method play = clazz.getMethod("play", String.class);// 获取类中指定名称和参数的公有方法
int modifiers = play.getModifiers();// 获取方法的修饰符
Object result = play.invoke(user, "紫川秀");// 指定对象进行成员方法的调用
play.setAccessible(true);// 指定方法的强制执行
Method playNoParam = clazz.getMethod("play");// 获取类中指定名称的公有方法
playNoParam.invoke(user);
playNoParam.invoke(null);// 静态方法调用
}
类的构造器操作
Constructor[] cons = clazz.getConstructors(); //获取类中所有的公有构造器
Constructor[] cons1 = clazz.getDeclaredConstructors(); //获取类中所有的构造器
Constructor conNoParam= clazz.getDeclaredConstructor(); //获取类中无参的构造器
Constructor con= clazz.getDeclaredConstructor(String.class,String.class); //获取类中有参构造
int modifers = con.getModifiers(); //获取构造器的修饰符
conNoParam.newInstance(); //构造器实例对象
con.setAccessible(true); //指定方法的强制访问
con.newInstance(“abc”,“bbb”); //有参构造调用
Person.class.newInstance(); //class直接调用默认无参构造
@Test
public void testConstructors() throws Exception {
Class<User> clazz = User.class;
Constructor<User> declaredConstructor = clazz.getDeclaredConstructor(String.class, String.class);
declaredConstructor.setAccessible(true);
User user1 = declaredConstructor.newInstance("idCard", "address");
User user2 = clazz.newInstance(); // 通过无参的构造函数反射出来的,无参的构造函数需要是public
System.out.println(user1);
System.out.println(user2);
}
构造器操作会对单例模式造成破坏