• 反射(类加载、加载流程、加载的五个阶段、获取类结构信息、反射暴破创建实例、操作属性、操作方法)


    动态和静态加载

    类加载

    反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。

    1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强

    2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性

    类加载时间:

    1.当创建对象时(静态加载)

    2.当子类被加载时,父类也加载(静态加载)

    3.调用类中的静态成员时(静态加载)

    4.通过反射(动态加载)

    类加载流程图

     1.加载Loading阶段:将类的class文件读入内存,并为之创建一个java.lang.Class对象,此过程由类加载器完成

    2.在连接Linking阶段:将类的二进制数据合并到JRE中

    3.初始化阶段:JVM负责对类进行初始化,该处主要是指静态成员

    类加载五个阶段

    加载阶段:

    JVM在该阶段的主要目的是将字节码从不同的数据源转化成二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

    连接阶段-验证:

    1.目的为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

    2.包括:文件格式验证(是否是魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证

    3.可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

    连接阶段-准备:

    JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始化值、如0,0L,null,false)

    连接阶段-解析:

    虚拟机将常量池内的符号引用替换为直接引用的过程

    初始化阶段:

    1.到初始化阶段,才真正开始执行类中定义的java程序代码,此阶段是执行()方法的过程

    2.()方法是由编译器按语句在源文件中出现的顺序、依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并

    3.虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕

    4.正因为有这个机制, 才能保证某个类在内存中,只有一份Class对象

    获取类结构信息

    第一组:java.lang.Class类

     第二组:java.lang.reflect.Field类

    1.getModifiers:以int形式返回修饰符(默认修饰符:0,public:1,private:2,               protected:4,static:8,final:16)

    2.getType:以Class形式返回类型

    3.getName:返回属性名

    第三组:java.lang.reflect.Method类

    1.getModifiers:以int形式返回修饰符(默认修饰符:0,public:1,private:2,    protected:4,static:8,final:16)

    2.getReturnType:以Class形式获取返回类型

    3.getName:返回方法名

    4.getParameterTypes:以Class[] 返回参数类型数组

    第四组:java.lang.reflect.Constructor类

    1.getModifiers:以int形式返回修饰符

    2.getName:返回构造器名(全类名)

    3.getParameterTypes:以Class[] 返回参数类型数组

    package com.jh.class_;

    //演示如何通过反射获取类的结构信息

    import org.junit.jupiter.api.Test;

    import java.lang.annotation.Annotation;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;

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

        }
      @Test
        public void api01() throws ClassNotFoundException {
            String path = "com.jh.class_.Mango";
            //得到class对象
            Class class01 = Class.forName(path);

            //1.getName:获取全类名
            System.out.println(class01.getName());//com.jh.class_.Mango

            //2.getSimpleName:获取简单类名
            System.out.println(class01.getSimpleName());//Mango

            //3.getFields:获取所有public修饰的属性,包含本来以及父类
              Field[] fields = class01.getFields();
              for (Field field : fields) {
                  System.out.println("本类及父类的public属性:" + field.getName());
              }
             /* 本类及父类的属性:name
              本类及父类的属性:shuiguo*/

            //4.getDeclaredFields:获取本类中所有属性
            Field[] declaredFields = class01.getDeclaredFields();
             for (Field declaredField : declaredFields) {
              System.out.println("本类中所有属性:" + declaredField.getName());
             }
             /* 本类中所有属性:name
             本类中所有属性:age
             本类中所有属性:address
             本类中所有属性:peach*/

            //5.getMethods:获取所有public修饰的方法,包括本类以及父类
              Method[] methods = class01.getMethods();
              for (Method method : methods) {
                  System.out.println("本类及父类的public修饰的方法:"+method.getName());
              }
              /*本类及父类的public修饰的方法:m1
              本类及父类的public修饰的方法:hi
              本类及父类的public修饰的方法:wait
              本类及父类的public修饰的方法:wait
              本类及父类的public修饰的方法:wait
              本类及父类的public修饰的方法:equals
              本类及父类的public修饰的方法:toString
              本类及父类的public修饰的方法:hashCode
              本类及父类的public修饰的方法:getClass
              本类及父类的public修饰的方法:notify
              本类及父类的public修饰的方法:notifyAll*/

              //6.getDeclaredMethods:获取本类中所有方法
              Method[] declaredMethods = class01.getDeclaredMethods();
              for (Method declaredMethod : declaredMethods) {
                  System.out.println("本类中所有的方法:" + declaredMethod.getName());
              }
              /*本类中所有的方法:m1
              本类中所有的方法:m2
              本类中所有的方法:m4
              本类中所有的方法:m3
              本类中所有的方法:hi*/

              //7.getConstructors:获取所有public修饰的构造器,包含本类
              Constructor[] constructors = class01.getConstructors();
              for (Constructor constructor : constructors) {
                  System.out.println("本类中public修饰的构造器:" + constructor.getName());
              }
              /*本类及其父类中public修饰的构造器:com.jh.class_.Mango
              本类及其父类中public修饰的构造器:com.jh.class_.Mango*/

              //8.getDeclaredConstructors:获取本类中所有构造器
              Constructor[] declaredConstructors = class01.getDeclaredConstructors();
              for (Constructor declaredConstructor : declaredConstructors) {
                  System.out.println("获取本类中所有构造器:" + declaredConstructor.getName());
              }
              /*获取本类中所有构造器:com.jh.class_.Mango
              获取本类中所有构造器:com.jh.class_.Mango
              获取本类中所有构造器:com.jh.class_.Mango*/

              //9.getPackage:以包名形式返回,包信息
              System.out.println("以包名形式返回包信息:" + class01.getPackage());
              /*以包名形式返回包信息:package com.jh.class_*/

              //10.getSuperclass:以Class形式返回父类信息
              Class superclass = class01.getSuperclass();
              System.out.println(superclass);
              /*class com.jh.class_.SuiGuo*/

              //11.getInterfaces:以Class形式返回接口信息
              Class[] interfaces = class01.getInterfaces();
              for (Class anInterface : interfaces) {
                  System.out.println("以Class形式返回接口信息:" + anInterface.getName());
              }
              /*以Class形式返回接口信息:com.jh.class_.IA
              以Class形式返回接口信息:com.jh.class_.IB*/

              //12.getAnnotations:以Annotations形式返回注解信息
              Annotation[] annotations = class01.getAnnotations();
              for (Annotation annotation : annotations) {
                  System.out.println("注解信息:" + annotation);
              }
              /*注解信息:@java.lang.Deprecated()*/


      }

    }

    反射暴破创建实例

    1.方式一:调用类中的public修饰的无参构造器

    1.方式二:调用类中的指定构造器

    3.Class类相关方法:

    (1.newInstance:调用类中的无参构造器,获取对应类的对象

        2.getConstructor(Class...):

        3.getDecalaredConstructor(Class...):根据参数列表,获取对应的所有构造器对象)

    4.Constructor:类相关方法

    setAccessible:暴破

    newInstance(Object...):调用构造器

    package com.jh.class_;

    //演示通过反射机制创建实例

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;

    @SuppressWarnings("all")
    public class ReflecCreateInstance {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

            //1.先获取User类的Class对象
            String path = "com.jh.class_.User";
            Class userclass = Class.forName(path);

            //2.通过public的无参构造器创建实例\
            Object o = userclass.newInstance();
            System.out.println(o);//User{age=23, name='tom'}

            //3.通过public的有参构造器创建实例
            //得到对应构造器
            Constructor constructor = userclass.getConstructor(String.class);
            //创建实例,传入实参
            Object jim = constructor.newInstance("jim");
            System.out.println(jim);//User{age=23, name='tom'}

            //4.通过非public的有参构造器创建实例
            //得到对应的构造器
            Constructor declaredConstructor =
                    userclass.getDeclaredConstructor(int.class, String.class);
            //暴破:使用反射可以访问private构造器
            declaredConstructor.setAccessible(true);
            //创建实例
            Object jason = declaredConstructor.newInstance(24, "jason");
            System.out.println(jason);//User{age=24, name='jason'}


        }
    }

    class User{
        private int age = 23;
        private String name = "tom";

        //无参构造器
        public User(){

        }

        //public的公有有参构造器
        public User(String name){

        }

        //有参构造器
        private User(int age, String name) {
            this.age = age;
            this.name = name;
        }

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

    反射暴破操作属性

    1.根据属性名获取Filed对象

    Filed  filed = class对象.getDeclaredFiled(属性名);

    2.暴破:filed.setAccessible(true);

    3.访问

    filed.set(o,值);//o是对象

    4.注意:如果是静态属性,则set和get中的参数o,可以写成null

    package com.jh.class_;

    //演示反射操作属性

    import java.lang.reflect.Field;

    @SuppressWarnings("all")
    public class ReflecAccessProperty {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {

            //1.得到Student类对应的Class对象
            String path = "com.jh.class_.Student";
            Class class01 = Class.forName(path);

            //2.创建对象
            Object o = class01.newInstance();

            //3.使用反射得到age属性对象
            Field age = class01.getField("age");
            age.set(o,24);
            System.out.println(o);//Student{age=24 null}

            //4.使用反射操作name
            Field name = class01.getDeclaredField("name");
            //对name进行暴破
            name.setAccessible(true);
            name.set(o,"tom");//因为name是static属性,因此o也可以写成null
            System.out.println(o);//Student{age=24 tom}
            

        }
    }

    class Student{
        public int age;
        private static String name;

        public Student(){

        }

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

    反射暴破操作方法

    1.根据方法和参数列表获取Method方法对象,Method m =  class01.getDeclaredMethod(方法名,xx.class);//得到本类的所有方法

    2.获取对象:Object o = class01.newInstance();

    3.暴破:m.setAccessible(true);

    4.访问:Object returnValue = m.invoke(o,实参列表);//o是对象

    5.注意:如果是静态方法,则invoke的参数o,可以写成null

    package com.jh.class_;

    //演示通过反射调用方法

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    @SuppressWarnings("all")
    public class ReflecAccessMethod {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

            //1.得到Boss类对应的Class对象
            String path = "com.jh.class_.Boss";
            Class class01 = Class.forName(path);

            //2.创建对象
            Object o = class01.newInstance();

            //3.调用public方法
            //得到hi对象
            Method hi = class01.getMethod("hi",String.class);
            Object jason = hi.invoke(o, "jason");
            //hi=jason

            //4.调用private static方法
            //得到方法对象
            Method say =
                    class01.getDeclaredMethod("say", int.class, String.class, char.class);
            //进行暴破
            say.setAccessible(true);
            //调用
            Object message = say.invoke(o, 24, "tom", '男');
            System.out.println(message);//24 tom 男

            //5.在反射中,如果方法有返回值,统一返回Object ,但是运行类型和方法定义的返回类型一致

        }
    }

    class Boss{
        public int age;
        private String name;

        public Boss(){

        }

        public void hi(String s){
            System.out.println("hi=" + s);
        }

        private static String say(int n,String s,char c){
            return n + " " + s + " " + c;
        }


    }

  • 相关阅读:
    为什么说企业需要数据可视化报表,浅谈数据可视化报表的真正价值
    「Verilog学习笔记」使用8线-3线优先编码器Ⅰ实现16线-4线优先编码器
    开发实战经验分享:互联网医院系统源码与在线问诊APP搭建
    【接口测试】微信小程序接口自动化的实现方案
    创建符合 Web 可访问性标准的 HTML 布局
    创建一个链表,用标准io读取文件数据插入链表,读取链表数据插入另一个文件
    day075:XML的约束:DTD约束文档、DTD约束文档的三种引入方法、DTD语法规则
    【pytorch】目标检测:一文搞懂如何利用kaggle训练yolov5模型
    git工作常用命令
    服务器扩容步骤
  • 原文地址:https://blog.csdn.net/weixin_46065214/article/details/126176593