注解与反射(二)

二  反射机制

反射的引入

如果添加配置文件re.properties指定信息,创建Cat对象并且调用hi方法 使用现有的技术该如何操作?

: 很明显现有的技术是需要改变源代码,创建对象 在利用对象调用hi方法这是十分麻烦的。

这样的需求在学习框架的时候是特别多,(通过外部文件配置,在不修改源代码的情况下,从而控制程序,符合设计模式当中的OCP原则(开闭原则:在不修改源码的情况下,扩展功能))

1 什么是反射

前提--基础知识:

静态语言与动态语言:

动态语言:

  • 在运行的时候代码可以根据某些条件改变自身的结构
  • 主要的动态语言:Object-c、C# 、Pthon

静态语言:

  • 与动态语言相对的,在运行时结构不可以改变的语言
  • 主要语言:java 、c 、c++

虽然说java是静态语言 但是java是可以被称为“准动态语言”的。java是有一定的动态性!

可以利用反射机制使java获得类似动态语言的特性。 也使得java的动态性让编程更具有灵活性!这也是java的市场价值所在!

1.1反射的含义

  • 反射(Rflection)是java被视为动态语言的关键所在.
  • 反射机制允许程序在执行期间借助Reflection API 取得任何类的内部信息,并且能够直接操作任意对象的内部属性以及方法

加载完类之后,

==>在堆内存当中的方法区会产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。

==>于是,我们可以通过这个对象看到类的结构。

==>这个对象就像一面镜子,通过这个镜子看到类的结构,所以我们形象的称之为:反射。

 

1.2反射的作用(为什么要反射)

可以在程序运行期间借助Reflection Api获取任何类的内部结构信息,并且能够操作任意对象修改内部属性和方法。这在传统的方式下是不可以的。

1.3反射的应用(通过反射机制可以获得什么(反射机制所提供的功能))

  1. 在运行期间可以构造一个类的对象
  2. 在运行期间可以获得一个类的所具有的成员变量和方法
  3. 在运行期间可以获取泛型信息
  4. 在运行期间可以处理注解
  5. 在运行期间可以判断任意一个对象的所属类
  6. 在运行期间可以调用任意对一个象的成员变量和方法
  7. 可以生成动态代理

1.4反射的主要类

  1. java.lang.Class:代表一个类 ,Class对象表示某个类加载后在堆中的对象。
  2. java.lang.reflection.Filed: 代表类的属性
  3. java.lang.reflection.Method :代表类的方法
  4. java.lang.reflection.Constructors :代表类的构造方法

1.5反射机制的优缺点

优点:可以动态的创建和使用对象(框架的核心),使用灵活

缺点:使用反射基本是解释执行,对执行速度有一定的影响。

   (对性能有影响,使用反射基本上是一种解释的操作,我们需要告诉jvm,我们希望做什么并且它能够满足我们的需求,这类操作总是慢于直接执行的操作)

1.6反射机制的性能优化

反射机制调优----关闭访问的检查:setAccessible(true)

  1. Filed、Method和Constructor对象都有setAccessible()方法。
  2. setAccessible()方法的作用是启动和禁用访问安全检查的开关
  3. 默认值是false 表示反射的对象执行访问检查 ;true表示反射的对象在执行时取消访问安全检查,提高了反射的效率。
public class ReflectionPerformanceOptimization {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        testTime1();
        testTime2();
        testTime3();
    }

//传统的通过new来创建对象
    public static void testTime1(){
        Cat cat1 = new Cat();
        cat1.cry();
        long start = System.currentTimeMillis();
        for(int i=0;i<=900000000;i++){
            cat1.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统的创建对象执行时间:"+(end-start));
    }


    public static void testTime2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class c1 = Class.forName("com.peng.pojo.Cat");
        Object o = c1.newInstance();
        Method methodName = c1.getMethod("hi");
        Method methodName2 = c1.getMethod("cry");
        long start = System.currentTimeMillis();
        for(int i=0;i<900000000;i++){
        methodName.invoke(o);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射机制的创建对象执行时间:"+(end-start));
    }


    public static void testTime3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class c1 = Class.forName("com.peng.pojo.Cat");
        Object o = c1.newInstance();

        Method methodName2 = c1.getMethod("hi");
        methodName2.setAccessible(true);//关闭访问安全检查
        long start = System.currentTimeMillis();
        for (int i=0;i<900000000;i++){
        methodName2.invoke(o);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射机制性能优化后创建对象执行时间:"+(end-start));


    }
}

1.7反射的原理图

2 Class类

这个Class就像一个镜子 十分重要!!!!!

2.1class的含义

Class对象实在加载类的时候由jvm就已经创建好了 所以 不需要我们创建只需要获取。

  1. Class也是类,只不过刚好这个类叫Class,也是继承于Object
  2. Class类不是new出来的,而是系统创建的,所以我们只需要获取。
  3. 对于某个类的Class对象,在内存当中只有一份,因为类只加载一次(通过ClassLoad类当中的loadclass加载的 在内存当中中有一份  涉及同步)
  4. 通过Class类可以完整的得到一个类的完整结构(一个类被加载后,类的整个结构都会被封装在Class对象(ReflectionClass中 ),通过一系列的API
  5. 每一个类的实例通过反射会记得它是由哪一个Class实例所身处个行的
  6. Class对象是放在堆
  7. 类的字节码二进制数据是放在方法区当中

2.2如何获取Class类(核心4种,总共6种)

2.2.1 Class.forName()

编译阶段-----

前提:已知一个类的全类名,且该类在类路径下,可以通过Class类的静态方法forName()获取

会抛出ClassNotFoundException错误

应用场景:多用于配置文件,读取类的全路径、加载类

2.2.2 类名.class

加载阶段---

前提:已知一个具体的类,通过class获取,该方式最为安全可靠 ,程序性能最高的

应用场景:多用于参数的传递 比如说通过反射活得对应的构造器对象

2.2.3 对象.getClass()

运行阶段---

前提:已知某个类的实例,调用该实例的getClasss()方法获取Class对象

应用场景:通过创建好的对象,获取Class对象

2.2.4 通过类加载器

类加载----

ClassLoader cl=对象.getClass().getClassLoader();

Class clazz4=cl.loadClass("类的全类名")

2.2.5 基本数据类型获取Class

Class cls5=基本数据类型.class

2.2.6基本数据类型的包装类的获取Class

Class cls6=包装类.TYPE

package com.peng.ClassLei;

import com.peng.pojo.Dog;

/*1获取Class类的方式
     (1)Class.forName()
     (2)Class类名.class
     (3)对象.getclass()
     (4)ClassLoader.loadclass()
     (5)基本数据类型.class
     (6)基本数据类型.TYPE
* */
public class Class02 {

    public static void main(String[] args) throws ClassNotFoundException {
        String classFullPath="com.peng.pojo.Dog";

        //方式一: 源码阶段 利用Class.forName()
        Class<?> c1 = Class.forName(classFullPath);
        System.out.println(c1);

        //方式二: 加载阶段 利用Class本类名.class
        Class<Dog> c2 = Dog.class;
        System.out.println(c2);
        //方式三:运行阶段  利用Dog类的实例对象.getClass()
        Dog dog=new Dog();
        Class c3 = dog.getClass();
        System.out.println(c3);
        //方式四: 类加载器  利用ClassLoader.loadclass()
        Class<?> c4 = dog.getClass().getClassLoader().loadClass(classFullPath);
        System.out.println(c4);

        //方式五:基本数据类型的  基本数据类型.class

        Class<Integer> c5 = int.class;
        System.out.println(c5);
        //方式六: 包装类的  基本数据类型.TYPE
        Class<Integer> c6 = Integer.TYPE;
        System.out.println(c6);

        System.out.println(c5.hashCode());
        System.out.println(c6.hashCode());
        //基本数据类型和其包装类 在反射当中会自动包装和拆箱
        ///
        //
        //
    }

}

2.3哪些类型可以获取Class类

  1. class:外部类 成员(成员内部类 静态内部类) 局部内部类 匿名内部类
  2. interface:接口
  3. [ ]:数组
  4. enum:枚举
  5. annotation :注解
  6. primitive type: 基本数据类型
  7. void
package com.peng.ClassLei;

import java.lang.annotation.ElementType;

//所有类型获取Class类(有哪些类型可以获取Class类)

public class Class03 {
    public static void main(String[] args) {

        Class c1= Object.class;//1所有类
        Class c2 = Comparable.class;//2接口
        Class c3 = Override.class;//3注解
        Class c4 = String[].class;//4数组  4.1一维数组
        Class c5 = String[][].class;//       4.2二维数组
        Class c6 = ElementType.class;//5枚举
        Class c7 = Integer.class; //6基本数据类型
        Class c8 = Class.class;//7Class本身
        Class c9 = void.class;//8void
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.hashCode());//460141958
        System.out.println(b.hashCode());//1163157884

        /*1  a和b获取Class的hashCode一样说明其类是同一个,
          2  a和b是其的实例化对象这也说明名了为什么a.hashCode和b.hashCode不一样
          3  只要元素类型和维度一致就是同一个Class
        * */
        System.out.println(a.getClass().hashCode());//1956725890
        System.out.println(b.getClass().hashCode());//1956725890

    }



}
  •         1 a和b获取Class的hashCode一样说明其类是同一个,
  •           2  a和b是其的实例化对象这也说明名了为什么a.hashCode和b.hashCode不一样
  •           3  只要元素类型和维度一致就是同一个Class

2.4Class类的常用方法

3 类加载

3.1基础知识点:

静态加载与动态加载的区别

静态加载:编译时加载相关的类,如果编译则报错,依赖性很强

动态加载:运行时加载相关的类,如果编译时不用该类就不会报错,即使不存在该类也不会报错 降低依赖性。

静态加载

静态加载编译

编译失败:

因为没有编写Dog类

静态加载就是在new 一个对象的时候 比如说 new Dog 但是Dog这个类没有编写 那么编译 javac ClassLoad.java 就会报错

动态加载

动态加载就是说 反射是动态加载 person类没有编写 在编译的时候是可以通过的 但是编译成功后运行java ClassLoad 的时候就是报错因为没有编写Person这个类 如果编写了这个类就会运行成功。

3.2类加载的过程

1 上图中的初始化时是与静态成员有关的 是类加载 而不是new 一个对象(创建一个对象)

2 类加载后内存当中堆区会有类的字节码二进制所对应的类的Class对象 (这是一个数据结构是一个接口)

注意事项:

  • 加载和链接阶段时在jvm虚拟机当中实现的不能人为干预。
  • 初始化阶段是程序员可以干涉的。
  • !!!类加载涉及到的都是一些静态成员!!!!!

3.2.1类加载-加载阶段

加载阶段是

==》将class字节码文件存到内存方法区当中

==》生成一个字节码二进制数据(将原本class字节码文件的静态数据转换为运行时的数据结构),

==》并且同时创建一个代表这个类的Class对象(堆区)。

3.2.2类加载-链接阶段

(1)验证子阶段

  • 目的 为了确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
  • 包括:文件格式验证(是否一魔教oxcafe babe开头)、元数据验证、字节码验证和符号引用验证
  • 可以使用-Xverify:none参数 来关闭大部分的类验证措施,缩短虚拟机类加载的时间

(2)准备子阶段

虚拟机会在准备阶段给静态变量分配内存并设置默认值(内存是在方法区当中分配的)

(3)解析子阶段

虚拟机将常量池当中符号引用(常量名)转变为直接引用(地址)的过程

2.1.3类加载-初始化阶段

  1. 到初始化阶段,才是真正的开始执行类中定义的java代码,这个阶段是执行clinit()放大的过程
  2. 类构造器clinit()方法是由编译器按顺序在源文件出现的次序,一次自动收集类中的所有静态变量的赋值动作和静态代码块的语句,并且进行合并(类构造器是构造类的信息不是,不是构造该类的对象的构造器)
  3. 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确的加锁、同步,如果多个线程同事去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,知道活动线程执行完毕。(这也说明了为什么在内存当中只有一个Class)

2.2内存分析类加载

2.3类加载时机

  1. 当创建一个对象(new)//静态加载
  2. 当子类被加载时,父类也会被加载 //静态加载
  3. 调用类的静态成员时 //静态加载
  4. 反射 //动态加载

2.4类加载器

2.4.1类加载器的作用:一句话把类(Class)装载进内存当中

将class字节码文件加载到内存当中 ,

==》并将这些静态数据转换成方法区运行时的数据结构

==》同时在堆区创建对应的class类对象,作为方法区中类数据的访问入口

2.4.2类缓存

标准的javaSE类加载器可以按要求查找类,但一旦某个类被加载类加载器当中,他将维持加载(缓存)一段时间,不过jvm垃圾回收机制(gc)可以回收这些Class对象。

2.4.3 jvm规范定义的类加载器类型

引导类加载器(跟加载器)----扩展类加载器----系统类的加载器--自定义类的加载器

/*//有哪些类加载器?
 //从上往下 超累==》父类==》子类
     引导类加载器(根加载器)
     扩展类加载器
     系统加载器()
     自定义加载器
     */
public class classloader01 {
    public static void main(String[] args) throws ClassNotFoundException {

        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        //获取系统类的加载器的父类加载器:扩展类加载器

        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
        //获取扩展类的加载器的父类夹杂其:根类加载器
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);


        //获取当前类的类加载器
        Class CatCls = Class.forName("com.peng.ClassLoad.ClassLoader.classloader01");
        ClassLoader classLoader = CatCls.getClassLoader();
        System.out.println(classLoader);

        //获取jdk内置的类的类加载器
        Class<?> c1 = Class.forName("java.lang.Object");
        ClassLoader classLoader1 = c1.getClassLoader();
        System.out.println(classLoader1);


        //获取系统类的类加载器的路径
        System.out.println(System.getProperty("java.class.path"));


    }



}

5 通过反射获取类结构信息(涉及反射的4种主要类)

1.java.lang.class类

@Test
public void Api_01() throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
    Class<?> Studentcls = Class.forName("com.peng.ClassLei.Student");

    //1 getName:获取全类名
    System.out.println("全类名==》"+Studentcls.getName());
    //2 getSimpleName:获取简单类名
    System.out.println("简单类名==》"+Studentcls.getSimpleName());
    System.out.println("============================");
    //3 getFields:获取所有public修饰的属性,包含本类以及父类的
    Field[] fields = Studentcls.getFields();
    for (Field field : fields) {
        System.out.println("本类及父类的public修饰的属性==》"+field.getName());
    }
    //4 getDeclaredFields:获取本类的所有属性

    Field[] declaredFields = Studentcls.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println("本类的所有属性==》"+declaredField.getName());
    }
    //5*********获取指定属性的值
    Field sno = Studentcls.getDeclaredField("sno");
    System.out.println(sno);
    System.out.println("============================");
    //6 getMethods:获取所有public修饰的方法,包含本类的以及父类(超类)的
    Method[] methods = Studentcls.getMethods();
    for (Method method : methods) {
        System.out.println("本类及父类的public修饰的方法==》"+method);
    }
    //7 getDeclaredMethods:获取苯类的所有方法
    Method[] declaredMethods = Studentcls.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        System.out.println("本类的所有方法==》"+declaredMethod);
    }
    //8***************获取指定方法
    Method m1 = Studentcls.getDeclaredMethod("m1", String.class);
    System.out.println(m1);


    System.out.println("============================");
    //9 getConstructors:获取本类的public修饰的构造器
    Constructor<?>[] constructors = Studentcls.getConstructors();
    for (Constructor<?> constructor : constructors) {
        System.out.println("本类的public修饰的构造器==>"+constructor);
    }

    //10 getDeclaredConstructors:获取苯类的所有构造器
    Constructor<?>[] declaredConstructors = Studentcls.getDeclaredConstructors();
    for (Constructor<?> declaredConstructor : declaredConstructors) {
        System.out.println("本类的所有构造器==>"+declaredConstructor);
    }

    //11 获取指定的构造器
    Constructor<?> declaredConstructor = Studentcls.getDeclaredConstructor(String.class, int.class);
    System.out.println(declaredConstructor);

    System.out.println("============================");
    //12 getPackage: 以Packgae形式返回包信息
    System.out.println("返回包信息==>"+Studentcls.getPackage());

    //13 getSuperClass:以Class形式返回父类信息
    System.out.println("返回父类信息==>"+Studentcls.getSuperclass());
    //14 getInterfaces:以Class[]形式返回接口信息
    Class<?>[] interfaces = Studentcls.getInterfaces();
    for (Class<?> anInterface : interfaces) {
        System.out.println("Class[]形式返回接口信息==>"+anInterface);
    }


    System.out.println("==================================");
    //15获取参数中是泛型的信息

    Method test1Method = Studentcls.getMethod("test1", Map.class, List.class);
    Type[] genericParameterTypes = test1Method.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        System.out.println(genericParameterType);
        if (genericParameterType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println("参数中是泛型的信息==>"+actualTypeArgument);
            }
        }
    }
    System.out.println("==================================");
    //16获取返回值类型是泛型的信息
    Method test2Method = Studentcls.getMethod("test12", null);
    Type genericReturnType = test2Method.getGenericReturnType();
    System.out.println(genericReturnType);
   if (genericReturnType instanceof ParameterizedType){
       Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
       for (Type actualTypeArgument : actualTypeArguments) {
           System.out.println("返回值类型是泛型的信息==>"+actualTypeArgument);
       }
   }
    System.out.println("==================================");
    //17 getAnnotations: 以Annotation[]形式返回注解信息
    Annotation[] annotations = Studentcls.getAnnotations();
    for (Annotation annotation : annotations) {
        System.out.println("Annotation[]形式返回注解信息==>"+annotation);
    }

//18获得注解的value的值
    db_table annotation1 = (db_table)Studentcls.getAnnotation(db_table.class);
    String value = annotation1.value();//字段上没有这个方法
    System.out.println("获得注解的value的值==>"+value);

}

2.java.lang.reflection.Field类

@Test
    public void Api_02() throws ClassNotFoundException {
    Class<?> Studentcls = Class.forName("com.peng.ClassLei.Student");

    //4 getDeclaredFields:获取本类的所有属性

    Field[] declaredFields = Studentcls.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println("本类的所有属性==》"+declaredField.getName()+"     本类所有属性的修饰符权限"+declaredField.getModifiers()
                            +"        本类所有属性返回的的类型"+declaredField.getType());
    }
}

2.java.lang.reflection.Method类

@Test
public void Api_03 () throws ClassNotFoundException {
    Class<?> Studentcls = Class.forName("com.peng.ClassLei.Student");
    Method[] declaredMethods = Studentcls.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        System.out.println("本类的所有方法==》"+declaredMethod+"    该方法的修饰符权限==>"+declaredMethod.getModifiers()
                            +"    该方法的返回值类型以Class形式==》"+declaredMethod.getReturnType());
        Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println("该方法的形参类型"+parameterType);
        }

    }
}

4.java.lang.reflection.Constructor类

//第四组接口测试 java.lang.reflection.Constructor
@Test
    public void Api_04() throws ClassNotFoundException {
    Class<?> Studentcls = Class.forName("com.peng.ClassLei.Student");
    Constructor<?>[] declaredConstructors = Studentcls.getDeclaredConstructors();
    for (Constructor<?> declaredConstructor : declaredConstructors) {
        System.out.println("本类的所有构造器==>"+declaredConstructor+"该构造器的修饰符权限"+declaredConstructor.getModifiers()
                              );
        Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println("     该构造器的参数类型以Class形式"+parameterType);
        }
    }
}

6如何动态创建一个对象(怎么反射?)

//动态创建对象执行方法   通过反射
public class DynamicallyCreateObjectsToExecuteMethods {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    }


    //本质上是调用了无参构造器从而动态创建对象
    @Test
        public void create1() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        String classFullPath = "com.peng.pojo.User";
        //获取user类的Class类对象
        Class userClass = Class.forName(classFullPath);
        //构造一个user对象实例
        User user1 = (User) userClass.newInstance();
        System.out.println(user1);  //User{name='null', id=0, age=0, sex='null'}
    }
    //通过有参的构造器来创建对象
    @Test
    public void create2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        String classFullPath="com.peng.pojo.User";
        //1 获取一个user类的Class类对象
        Class userClass = Class.forName(classFullPath);

        //2 通过构造器来创建对象
        //2.1先选择构造器
        Constructor Constructor = userClass.getDeclaredConstructor(String.class, int.class, int.class, String.class);
        //2.2 以构造器为对象 来newInstance
        User user2 = (User) Constructor.newInstance("1号", 0001, 18, "女");
        System.out.println(user2);
    }

    //通过反射调用普通方法  从而给其动态改变值
    @Test
    public void methodsAreInvokedThroughReflection() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

        String classFullPath="com.peng.pojo.User";
        //1 获取一个user类的Class类对象
        Class userClass = Class.forName(classFullPath);
        //2 创建一个User对象实例化
        User user3 = (User)userClass.newInstance();
        //3 通过Class类对象来获取指定的普通方法
        Method setName = userClass.getDeclaredMethod("setName", String.class);
        setName.invoke(user3, "3号");//invoke(对象,“方法的值”)
        System.out.println(user3.getName());
    }

    /*//通过反射调用属性
    @Test
    public void fieldThroughReflection() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {

        String classFullPath="com.peng.pojo.User";
        //1 获取一个user类的Class类对象
        Class userClass = Class.forName(classFullPath);
        //2 创建一个User对象实例化
        User user4 = (User)userClass.newInstance();
        //3 通过Class类对象来获取指定的字段

        Field name = userClass.getDeclaredField("name");

        name.set(user4,"4号");
        System.out.println(user4.getName());
    }
    //会报错
    // Class com.peng.Reflection.
    // DynamicallyCreateObjectsToExecuteMethods can not access a member of class com.peng.pojo.User with modifiers "private"
    //User类当中的属性是私有的 正常情况下是不能被访问的  但是在反射当中我们可以通过 setAccessible 来设置关闭 安全检查 涉及链接-验证子阶段
*/

    //通过反射调用属性
    @Test
    public void fieldThroughReflection() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {

        String classFullPath="com.peng.pojo.User";
        //1 获取一个user类的Class类对象
        Class userClass = Class.forName(classFullPath);
        //2 创建一个User对象实例化
        User user5 = (User)userClass.newInstance();
        //3 通过Class类对象来获取指定的字段

        Field name = userClass.getDeclaredField("name");
        //不能直接操作私有属性,需要关闭程序的安全检测,属性或者方法的setAccessible(true)
        name.setAccessible(true);
        name.set(user5,"5号");
        System.out.println(user5.getName());
    }
    //会报错
    // Class com.peng.Reflection.
    // DynamicallyCreateObjectsToExecuteMethods can not access a member of class com.peng.pojo.User with modifiers "private"
    //User类当中的属性是私有的 正常情况下是不能被访问的  但是在反射当中我们可以通过 setAccessible 来设置关闭 安全检查 涉及反射机制的性能优化
    // 搞混点在于类加载-链接-验证当中有一个Xverify(none)可以关闭大部分验证 降低时间
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值