美文网首页
反射专题

反射专题

作者: 攻城老狮 | 来源:发表于2021-05-28 08:15 被阅读0次

1 反射机制

1.1 Java程序的三阶段

image-20210526212134502.png

1.2 反射的优缺点

  • 优点:可以动态创建和使用对象(底层框架核心),使用灵活,没有反射机制,框架就失去底层支撑
  • 缺点:使用反射基本是解释执行,对执行速度有影响
//测试使用new,反射和优化后的反射,执行方法的速度
public class SpeedTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        m1();
        m2();
        m3();
    }

    //使用传统new对象的方式
    public static void m1() {
        Person person = new Person();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            person.sayHi();
        }
        long end = System.currentTimeMillis();
        System.out.println("m1: " + (end - start));
    }

    //使用反射的方式
    public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> personClass = Class.forName("com.yqj.domain.Person");
        Object person = personClass.newInstance();
        Method sayHi = personClass.getMethod("sayHi");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            sayHi.invoke(person);
        }
        long end = System.currentTimeMillis();
        System.out.println("m2: " + (end - start));
    }

    //使用优化后的反射
    //1.Method,Field,Constructor 对象都有 setAccessible() 方法
    //2.setAccessible 作用是启动和禁用访问安全检查的开关,true为取消访问检查,false开启
    public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> personClass = Class.forName("com.yqj.domain.Person");
        Object person = personClass.newInstance();
        Method sayHi = personClass.getMethod("sayHi");
        sayHi.setAccessible(true);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            sayHi.invoke(person);
        }
        long end = System.currentTimeMillis();
        System.out.println("m2: " + (end - start));
    }
}
  • result
m1: 5
m2: 2988
m2: 1888

2 Class类

2.1 基本说明

  • Class也是类,也继承Object类
  • Class类对象不是new出来的,而是系统创建的
//ClassLoader 类,不管是new还是反射的方法,第一次创建对象时候均需要通过该类创建单例的Class对象
public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
  • 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
Person person1 = new Person();
Person person2 = new Person();
System.out.println(person1.getClass().hashCode()); //hashCode一致说明是同一个对象
System.out.println(person2.getClass().hashCode());
  • 每个类的实例都会记得自己是由哪个Class实例所生成( getClass方法)
  • 通过Class对象可以完整地得到一个类的完整结构,通过API
  • Class对象存放在堆中
  • 类的字节码二进制数据放在方法区,或称为类的元数据

2.2 Class类的常用方法

getMethod()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法

getDeclaredMethod()返回表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法

public class ClassBaseMethod {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        String classPath = "com.yqj.domain.Person";
        //1.获取Person类对应的Class对象
        Class<?> personClass = Class.forName(classPath);
        //2.输出Class
        System.out.println(personClass); //显示哪个类的Class对象
        System.out.println(personClass.getClass()); //显示Class本身
        //3.得到包名
        System.out.println(personClass.getPackage().getName());
        //4.得到全类名
        System.out.println(personClass.getName());
        //5.创建对象实例
        Person person = (Person) personClass.newInstance();
        System.out.println(person);
        //6.通过反射获取属性
        //可以获取包括私有属性
        Field age = personClass.getDeclaredField("age");
        age.setAccessible(true); //允许访问私有属性
        age.set(person,24);
        System.out.println(age.get(person));
        //类似方法
//        personClass.getDeclaredMethod();
//        personClass.getMethod();
//        personClass.getDeclaredConstructor()
//        personClass.getConstructor()
    }
}

2.3 获取Class对象的方法

public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.已知类的全类名,且该类在类路径下,可通过Class静态方法forName获取
        //多用于配置文件,读取类全路径,加载类
        Class personClass1 = Class.forName("com.yqj.domain.Person");
        System.out.println(personClass1);
        //2.若已知具体的类,通过类的class获取,安全且程序性能最高
        //多用于参数传递,比如通过反射得到对应的构造器对象
        Class personClass2 = Person.class;
        System.out.println(personClass2);
        //3.已知某个类的实例,通过getClass方法获取Class对象
        //通过创建好的对象,获取Class对象
        Class personClass3 = new Person().getClass();
        System.out.println(personClass3);
        //4.通过类加载器获取Class对象
        Class personClass4 = new Person().getClass().getClassLoader().loadClass("com.yqj.domain.Person");
        System.out.println(personClass4);
        //5.基本数据类型通过class获取
        Class intClass = int.class;
        System.out.println(intClass);
        //6.包装类通过TYPE获取其基本类型的Class对象
        Class integerClass = Integer.TYPE;
        System.out.println(integerClass);
    }
}

2.4 具有Class对象的类型

  • 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
  • interface接口
  • 数组
  • enum枚举
  • annotation注解
  • 基本数据类型
  • void

2.5 类加载各阶段任务

image-20210527084625015.png
  1. 加载阶段:JVM在该阶段将字节码从不同的数据源(class文件,jar包,网络)转换为二进制字节流加载至内存中,并生成一个代表该类的Class对象
  2. 连接阶段-验证:为了确保Class文件字节流中包含的信息符合当前虚拟机的要求,包括对文件格式的验证,元数据验证,字节码验证和符号引用验证,可通过 -Xverify:none 关闭
  3. 连接阶段-准备:JVM在该阶段对静态变量分配内存并默认初始化(0,0L,null,false),这些变量所使用的内存在方法区分配
  4. 连接阶段-解析:JVM将常量池内的符号引用替换为直接引用的过程
  5. Initialization初始化:此阶段执行<clinit>() 方法,该方法依次收集类中所有静态变量的赋值动作和静态代码块中的语句,并按顺序进行合并。JVM包装该方法在多线程环境中被正确加锁同步

2.6 通过反射获取结构信息

1. Class类
getName()
getSimpleName()
getFields() 获取所有public修饰的属性,包含本类和父类
getDeclaredFields() 获取本类所有属性
getMethods()
getDeclaredMethods()
getConstructors()
getDeclaredConstructors()
getPackage()
getSuperClass()
getInterfaces()
getAnnotations()

2. Field类
getModifiers() 以int形式返回修饰符,默认修饰符0,public1,private2,protected4,static8,final16,若 public1 + static8 = 9
getType()
getName()

3. Method类
getModifiers()
getReturnType()
getName()
getParameterTypes()

4. Constructor类
getModifiers()
getName()
getParameterTypes()

相关文章

  • 反射专题

    1 反射机制 1.1 Java程序的三阶段 1.2 反射的优缺点 优点:可以动态创建和使用对象(底层框架核心),使...

  • 经典Java面试题的答案——反射

    大家好,我是九神。这是互联网技术岗的分享专题,废话少说,进入正题: 57.什么是反射? 反射主要是指程序可以访问、...

  • 【Android架构师java原理专题详解】二;反射原理及动态代

    前言; 本篇为Android架构师java原理专题二;反射原理及动态代理模式。大公司面试都要求我们有扎实的Java...

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • 镜面反射矩阵的推导

    镜面反射是以镜面作为反射平面,实物与反射物到反射平面的距离相等,实物与反射物方向相反,所以,反射矩阵由反射平面确定...

  • reflect.go包学习_之二 指针操作提高反射性能 反射应用

    reflect.go包学习_之二 指针操作提高反射性能 反射应用 反射创建实例 反射信息、反射调用方法、反射修改值...

  • Java互联网公司-经典面试题附答案

    基础:Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?优点:反射具有解耦性,缺点:反射属...

  • Java反射与joor反射库的使用

    java原生反射的使用 反射构造对象 反射方法 反射字段 joor反射库的使用 github:https://gi...

  • Java反射

    什么是反射? 反射的作用? 反射性能优化?

  • 反射三定律

    反射第一定律:反射可以将interface类型变量转换成反射对象 反射第二定律:反射可以将反射对象还原成inter...

网友评论

      本文标题:反射专题

      本文链接:https://www.haomeiwen.com/subject/igdrsltx.html