使用反射操作资源(二十七)

使用反射操作资源(二十七)

类的加载过程

Java中的类是怎样被加载最终被我们使用的呢,在Java中类的记载过程总体分为3步:

  1. 装载:查找到类并将类的数据转化成二进制格式保存
  2. 链接:
    1. 验证:检查类中的格式是否有问题,或者是否有安全问题等
    2. 准备:为类中的静态变量分配内存,并给初始化的值
    3. 解析:把类中的符号引用转换成直接引用
  3. 初始化:将真正的值赋给类中的静态变量

类在什么情况化会被初始化?

  1. 创建类的实例,即new出一个实例
  2. 访问一个类或接口的静态变量,或者对静态变量赋值
  3. 调用类的静态方法
  4. 反射Class.forName()
  5. 初始化一个子类会先初始化它的父类
  6. 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
posted @ 2021-03-09 23:10  LucaZ  阅读(29)  评论(0编辑  收藏  举报