Java 反射

Java 反射

正常的类加载过程

  1. 当执行new xxx();语句时,JVM会被触发加载.class文件
  2. JVM从本地文件找到class文件并且加载到内存中
  3. JVM自动创建一个class对象 (一个类只产生一个class对象)
  4. 将Java的二进制代码合并到JVM的运行状态之中
    • 验证: 确保类的信息符合JVM规范,没有安全问题
    • 准备: 正式为类变量分配内存并设置默认初始值(都在方法区进行分配)
    • 解析: 虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
  5. 初始化

JAVA内存分析

    • 存放new的对象和数组
    • 可以被所有的线程共享,不会存放别的对象引用
    • 存放基本变量类型
    • 引用对象的变量
  • 方法区
    • 可以被所有的线程共享
    • 包含了所有的class和static变量

类加载

PS: 这里仅仅是大概、其中省略了某些步骤

  • 加载
    • 将类中的静态变量、方法等重新构建成一个新的数据结构
      • 生成Class对象
  • 验证
  • 分配内存
    • 为类变量分配内存,设置初始值,在方法区中进行分配
  • 解析
    • 将变量替换成直接引用
  • 初始化
    • 执行 方法:编译器按照顺序,依次收集类变量的赋值语句以及static块中的语句整合产生
public class Test04 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.m);
    }
}
class A {
    static {
        System.out.println("A -- static");
        m = 100;
    }
    static int m = 200;
    public A() {
        System.out.println("A -- construct");
    }
}
// A -- static
// A -- construct
// 200

public class Test04 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.m);
    }
}
class A {
    static int m = 200;
    static {
        System.out.println("A -- static");
        m = 100;
    }
    public A() {
        System.out.println("A -- construct");
    }
}
// A -- static
// A -- construct
// 100

优缺点

优点:

  • 在运行时获得类的各种内容,进行反编译,代码可以在运行时装配

缺点:

  • 消耗资源
  • 安全问题

反射本质

得到class对象,反向获取实体对象的各种信息

反射机制

将类的各个组成部分封装成其他对象

优点

  1. 可以在程序运行过程中操作这些对象、
  2. 解耦

获取Class对象的方式

  1. Class.forName("全类名"); // 将字节码文件加载到内存,返回Class对象 多用于配置文件
  2. 类名.class // 通过类名属性class获取 多用于参数传递
  3. 对象.getClass() // Object中定义了方法 多用于对象的获取字节码方式
package reflection;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

import java.security.PublicKey;

public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();      // 所对应的Class是Person而非Student
        Student student = new Student();
        Teacher teacher = new Teacher();
        System.out.println("This is " + person.name);

        // 通过对象获得
        Class c1 = person.getClass();

        // forname
        Class c2 = Class.forName("reflection.Student");

        // 通过类名.class
        Class<Student> c3 = Student.class;

        // 基本内置类型的包装类有一个Type属性
        Class c4 = Integer.TYPE;

        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());

        // 获取父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);

        Class c6 = teacher.getClass();
        Class c7 = student.getClass();
        System.out.println("teacher " + c6);
        System.out.println("teacher hash " + c6.hashCode());
        System.out.println("teacher super hash " + c6.getSuperclass().hashCode());
        System.out.println("student hash " + c7.hashCode());
        System.out.println("student super hash " + c7.getSuperclass().hashCode());

    }
}


class Person {
    public String name;

    public Person(String name) {
        this.name = name;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

class Student extends Person {
    public Student() {
        this.name = "Student";
    }
}

class Teacher extends Person {
    public Teacher() {
        this.name = "Teacher";
    }
}

使用Class对象

获取属性

  • 获取成员变量

  • 获取构造方法

 public Constructor<?>[] getConstructors()				// 获取所有的Public构造方法
 public Constructor<?>[] getDeclaredConstructors()		// 获取所有的构造方法(所 有 !)
 public Constructor<T> getConstructor(Class<?>... parameterTypes)	//获取单个共有的构造方法
 public Constructor<T> getDeclaredConstructor(Class... parameterTypes)	//获取某个构造方法(任意)
  • 获取成员方法
  • 获取类名

用反射机制创建实例

  1. Class对象的newInstance
Class c = String.class;
Object str = c.newInstance();
str += "123456";
System.out.println(str);
  1. 获取Constructor,通过Constructor创建实例
// Person.java	(Person类)
private String name;
private int age;
public Person(String name, int age) {
    this.name = name;
    this.age = age;
}


// 创建实例 Test.java  (主类)
// 获取Class对象
Class<?> p = Person.class;
// 通过获取的Class对象获取Constructor对象 (其中里面依次填入的是参数类型)
Constructor<?> constructor = p.getConstructor(String.class, int.class);
// 根据Constructor创建实例
Object person = constructor.newInstance("szx", 19);
System.out.println(person);
posted @ 2020-11-06 20:59  退役的熬夜选手  阅读(73)  评论(0编辑  收藏  举报