Java 反射技术总结

反射

简介

  • 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性
  • 静态语言:是一种可以在运行时改变其结构的语言
  • 静态语言:运行时结构不可变
  • 加载完类之后,再堆内存中的方法区中产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类型结构。所以我们称之为反射

创建Class对象

@Test
public void test() throws ClassNotFoundException {
    // 方式一: 类名.class
    Class<Book> bookClass = Book.class;
    // 方式二: 对象.getClass()
    Class<? extends Book> aClass = new Book().getClass();
    // 方式三: 通过包名来获得Class对象
    Class<?> aClass1 = Class.forName("com.demo07.Book");
}

类的加载

  • 加载:
    • 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象。
  • 链接:
    • 验证:将java类的二进制代码合并到JVM的运行状态中的过程
    • 准备:正式将类变量(static)分配到内存中并设置类变量默认初始值的阶段,这些内存都将在方法去中进行分配。
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
  • 初始化:
    • 执行类构造器()方法的过程,类构造器()方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
    • 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步

类的初始化

  • 类的主动引用(一定会发生的类的初始化):
    • 当虚拟机启动,先初始化main方法所在的类
    • new 一个类的对象
    • 调用类的静态变量(除了final常量)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射调用
    • 当初始化一个类,如果其父类没有初始化,则会初始化他的父类
  • 类的被动引用(背会发生类的从初始化)
    • 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类被初始化
    • 通过数据定义类应用,不会触发此类的初始化
    • 引用常量不会触发类的初始化(常量在链接阶段就存入调用类的常量池中)

类加载器

  • 作用:

    • 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆内存中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
  • 类缓存:

    • 标准的javaSE类加载器可以按照要求查找类,但一旦某个类被加载到类加载器中,他讲维持加载(缓存)一段时间

获取类的运行时结构

@Test
public void test3() throws Exception {
    // 获取class对象
    Class<?> aClass = Class.forName("com.demo07.Book");
    // 后驱构造方法
    Constructor<?> constructor = aClass.getDeclaredConstructor(String.class, Double.class);
    // 一致java语言访问检查
    constructor.setAccessible(true);
    // 创建对象
    Book book = (Book) constructor.newInstance("未来简史", 45.0);
    System.out.println(book.toString());

    // 获取当前类中所有public修饰的属性
    Field[] fields = aClass.getFields();
    // 获取当前类中的所有字段
    Field[] declaredFields = aClass.getDeclaredFields();
    // 获取当前类及父类中所有被public修饰的方法
    Method[] methods = aClass.getMethods();
    // 获取类中所有的方法
    Method[] declaredMethods = aClass.getDeclaredMethods();
    // 获取指定方法
    Method setBookName = aClass.getDeclaredMethod("setBookName", String.class);
    setBookName.setAccessible(true);
    // 调用方法: 传入参数:目标对象,参数
    setBookName.invoke(book, "时间简史");
    Method getBookName = aClass.getDeclaredMethod("getBookName");
    getBookName.setAccessible(true);
    System.out.println(getBookName.invoke(book));

    // 获取类上指定注解
    Table table = (Table) aClass.getAnnotation(Table.class);
    System.out.println(table.value());
    Field bookName = aClass.getDeclaredField("bookName");
    // 获取字段上的指定注解
    Colnum colnum = bookName.getAnnotation(Colnum.class);
    System.out.println(colnum.name());
    System.out.println(colnum.type());
    System.out.println(colnum.lenght());
}

你可能感兴趣的:(Java,java,反射)