反射专题

2021-05-28  本文已影响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));
    }
}
m1: 5
m2: 2988
m2: 1888

2 Class类

2.1 基本说明

//ClassLoader 类,不管是new还是反射的方法,第一次创建对象时候均需要通过该类创建单例的Class对象
public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
Person person1 = new Person();
Person person2 = new Person();
System.out.println(person1.getClass().hashCode()); //hashCode一致说明是同一个对象
System.out.println(person2.getClass().hashCode());

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对象的类型

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()
上一篇 下一篇

猜你喜欢

热点阅读