使用反射操作资源(二十七)
使用反射操作资源(二十七)
类的加载过程
Java中的类是怎样被加载最终被我们使用的呢,在Java中类的记载过程总体分为3步:
- 装载:查找到类并将类的数据转化成二进制格式保存
- 链接:
- 验证:检查类中的格式是否有问题,或者是否有安全问题等
- 准备:为类中的静态变量分配内存,并给初始化的值
- 解析:把类中的符号引用转换成直接引用
- 初始化:将真正的值赋给类中的静态变量
类在什么情况化会被初始化?
- 创建类的实例,即new出一个实例
- 访问一个类或接口的静态变量,或者对静态变量赋值
- 调用类的静态方法
- 反射Class.forName()
- 初始化一个子类会先初始化它的父类
- Main方法类
使用反射方式操作类中资源
package com.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 获取Student类的类对象
Class studentClass = Class.forName("com.reflect.Student");
// 获取类中的属性
Field[] fields = studentClass.getFields();
for (Field f: fields) {
System.out.println(f);
}
System.out.println("====================");
// 获取类中的所有属性,包括私有属性
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field f: declaredFields) {
System.out.println(f);
}
System.out.println("====================");
// 获取指定的属性
Field name = studentClass.getDeclaredField("name");
System.out.println(name);
System.out.println("====================");
// 获取Student类中的指定方法
Method getName = studentClass.getMethod("getName");
System.out.println(getName);
System.out.println("====================");
// 获取类中的构造方法
Constructor constructor = studentClass.getConstructor(String.class, int.class);
System.out.println(constructor);
// 通过构造方法生成Student实例
Student xm = (Student)constructor.newInstance("小明", 20);
// 通过实例调用方法
Method setAge = studentClass.getMethod("setAge", int.class);
setAge.invoke(xm, 23);
Method getAge = studentClass.getMethod("getAge");
int age = (int) getAge.invoke(xm);
System.out.println(age);
}
}
class Person {
}
class Student extends Person {
private String name;
public int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
使用反射获取注解
package com.reflect;
import java.lang.annotation.*;
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("com.reflect.TestClass5");
// 反射获取所有的注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation a: annotations) {
System.out.println(a);
}
System.out.println("=====================");
// 获取指定名字的注解
TestAnnotation annotation = (TestAnnotation)c1.getAnnotation(TestAnnotation.class);
// 获取注解的值
String value = annotation.value();
System.out.println(value);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
String value() default "test";
}
@TestAnnotation("T5")
class TestClass5 {}
使用反射方式性能损耗
在下面的例子中,分别使用1. 正常实例化对象,2. 调用实例方法,3. 使用反射方式调用方法,并关闭校验三种方式调用,看看在循环中的性能情况。
package com.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test04 {
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException {
test01();
test02();
test03();
}
public static void test01 () {
Student2 s1 = new Student2("小明");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
s1.getName();
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
}
public static void test02 () throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
// 反射获取Student2类
Class c1 = Class.forName("com.reflect.Student2");
long startTime = System.currentTimeMillis();
// 获取Student2类的构造方法并创建实例
Object xm = c1.getConstructor(String.class).newInstance("小明");
// 通过方法名获取方法
Method getName = c1.getMethod("getName");
for (int i = 0; i < 10000000; i++) {
// 运行实例的方法
getName.invoke(xm);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
}
public static void test03 () throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class c1 = Class.forName("com.reflect.Student2");
long startTime = System.currentTimeMillis();
Object xm = c1.getConstructor(String.class).newInstance("小明");
Method getName = c1.getMethod("getName");
// 取消反射的检查,一定程度上提升反射效率
getName.setAccessible(true);
for (int i = 0; i < 10000000; i++) {
getName.invoke(xm);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
}
}
class Student2 {
private String name;
public Student2() {
}
public Student2(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
'}';
}
}
下面是运行的结果,可以看到使用反射的方式会很明显的降低程序运行的性能,关闭反射的检查会在一定程度上提升性能。
4
2286
51
Process finished with exit code 0