Java反射:框架设计的灵魂

  • java 代码在计算机中经历的阶段

    • 编写源代码:首先,你需要使用文本编辑器或集成开发环境(IDE)编写Java源代码文件。源代码是以.java文件扩展名保存的文本文件,包含了Java编程语言的语法和逻辑。
    • 编译源代码:一旦源代码编写完成,你需要使用Java编译器(javac命令)将源代码编译成字节码文件。编译器将检查语法错误、类型检查等,并将源代码翻译成平台无关的字节码。
    • 字节码文件:编译完成后,生成的字节码文件以.class文件扩展名保存。这些文件包含了Java虚拟机(JVM)可以理解和执行的指令。
    • 类加载:在运行Java程序之前,JVM需要将字节码加载到内存中。类加载器负责加载字节码文件,并将其转换为运行时的类对象。类加载器按需加载类,确保类在首次使用之前被加载。
    • 字节码验证:在加载字节码文件后,JVM会对字节码进行验证,以确保其符合Java虚拟机的安全和规范要求。验证过程包括类型检查、访问权限验证、指令验证等。
    • 解释和执行:一旦字节码通过验证,JVM将使用解释器或即时编译器(JIT编译器)来执行字节码指令。解释器逐条解释字节码指令并执行,而即时编译器将热点代码编译成本地机器码以提高执行性能。
    • 运行时优化:在执行过程中,JVM还会进行运行时优化。它使用各种技术,如方法内联、垃圾回收、逃逸分析等,来改善程序的性能和内存管理。
    • 程序输出:一旦程序执行完成,它可以产生输出,如控制台输出或写入文件。这些输出是根据程序的逻辑和代码来生成的。
    • 总体来说,Java代码的执行经历了编写源代码、编译、类加载、验证、解释/编译执行以及运行时优化等阶段,最终产生程序的输出结果。这个过程是由Java虚拟机负责管理和执行的
      在这里插入图片描述
  • Java反射的原理

  • 简述:将类的各个组成部分封装为其他对象,这就是反射机制
    • 获取Class对象:Java反射的入口是通过获取类的Class对象。Class对象包含了类的完整结构信息,包括类的名称、父类、接口、字段、方法等。
      Class<?> clazz = ClassName.class; // 或者 Class<?> clazz = Class.forName(“package.ClassName”);

    • 类加载器:在Java中,类的加载是由类加载器(ClassLoader)负责的。类加载器根据类的名称查找并加载对应的字节码文件,并将其转换为一个或多个Class对象。类加载器可以从文件系统、网络、JAR文件等位置加载类。

    • Class对象的创建:当类加载器加载类的字节码文件后,会将其转换为一个Class对象。该Class对象包含了类的所有信息,并被存储在方法区(Method Area)中。

    • 类信息的存储:在方法区中,JVM会存储类的结构信息,包括字段、方法、构造函数、注解等。这些信息可以通过Class对象的方法进行访问和操作。

    • 访问和操作类的成员:通过Class对象,可以获取类的字段、方法、构造函数等成员对象,并进行调用和操作。Java反射提供了一系列的方法,如getMethods()、getField()、getMethod()等,用于获取和操作类的成员。

    • 动态创建对象和调用方法:使用Class对象,可以动态地创建类的实例,并调用类的方法。通过newInstance()方法可以创建对象,通过invoke()方法可以调用方法。

    Person.java:
    package com.test;
    
    public class Person {
        private String name;
        private int age;
    
        public String a;
        protected String b;
        String c;
        private String d;
    
    
        public Person() {
        }
    
        public Person(String name, int age) {
    
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", a='" + a + '\'' +
                    ", b='" + b + '\'' +
                    ", c='" + c + '\'' +
                    ", d='" + d + '\'' +
                    '}';
        }
    
    
        public void eat(){
            System.out.println("eat...");
        }
    
        public void eat(String food){
            System.out.println("eat..."+food);
        }
    }
    
    
    
    ReflectDemo1.java:
    public class ReflectDemo1 {
    
    
        /**
            获取Class对象的方式:
                1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
                	多用于配置文件,将类名定义在配置文件中。读取文件,加载类
                2. 类名.class:通过类名的属性class获取
                	多用于参数的传递
                3. 对象.getClass():getClass()方法在Object类中定义着
                	多用于对象的获取字节码的方式
    			结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一
         */
        public static void main(String[] args) throws Exception {
    
            //1.Class.forName("全类名")
            Class cls1 = Class.forName("com.test.Person");
            System.out.println(cls1);
            //2.类名.class
            Class cls2 = Person.class;
            System.out.println(cls2);
            //3.对象.getClass()
            Person p = new Person();
            Class cls3 = p.getClass();
            System.out.println(cls3); 
    
            //== 比较三个对象
            System.out.println(cls1 == cls2);//true
            System.out.println(cls1 == cls3);//true
    
    
            Class c = Student.class;
            System.out.println(c == cls1);
    
    
        }
    }
    
    
  • Class对象功能:

    • 获取功能:
      1. 获取成员变量们
        • Field[] getFields() :获取所有public修饰的成员变量

        • Field getField(String name) 获取指定名称的 public修饰的成员变量

        • Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

        • Field getDeclaredField(String name)

      2. 获取构造方法们
        • Constructor<?>[] getConstructors()

        • Constructor getConstructor(类<?>… parameterTypes)

        • Constructor getDeclaredConstructor(类<?>… parameterTypes)

        • Constructor<?>[] getDeclaredConstructors()

      3. 获取成员方法们:
        • Method[] getMethods()

        • Method getMethod(String name, 类<?>… parameterTypes)

        • Method[] getDeclaredMethods()

        • Method getDeclaredMethod(String name, 类<?>… parameterTypes)

      4. 获取全类名
        • String getName()
      public class ReflectDemo2 {
      
      
          public static void main(String[] args) throws Exception {
      
              //0.获取Person的Class对象
              Class personClass = Person.class;
              /*
                   1. 获取成员变量们
                       * Field[] getFields()
                       * Field getField(String name)
      
                       * Field[] getDeclaredFields()
                       * Field getDeclaredField(String name)
      
               */
              //1.Field[] getFields()获取所有public修饰的成员变量
              Field[] fields = personClass.getFields();
              for (Field field : fields) {
                  System.out.println(field);
              }
      
              System.out.println("------------");
              //2.Field getField(String name)
              Field a = personClass.getField("a");
              //获取成员变量a 的值
              Person p = new Person();
              Object value = a.get(p);
              System.out.println(value);
              //设置a的值
              a.set(p,"张三");
              System.out.println(p);
      
              System.out.println("===================");
      
              //Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
              Field[] declaredFields = personClass.getDeclaredFields();
              for (Field declaredField : declaredFields) {
                  System.out.println(declaredField);
              }
              //Field getDeclaredField(String name)
              Field d = personClass.getDeclaredField("d");
              //忽略访问权限修饰符的安全检查
              d.setAccessible(true);//暴力反射
              Object value2 = d.get(p);
              System.out.println(value2);
              
              
              
              
              
              
                //Constructor<T> getConstructor(类<?>... parameterTypes)
              Constructor constructor = personClass.getConstructor(String.class, int.class);
              System.out.println(constructor);
              //创建对象
              Object person = constructor.newInstance("张三", 23);
              System.out.println(person);
      
              System.out.println("----------");
      
      
              Constructor constructor1 = personClass.getConstructor();
              System.out.println(constructor1);
              //创建对象
              Object person1 = constructor1.newInstance();
              System.out.println(person1);
      
              Object o = personClass.newInstance();
              System.out.println(o);
      
      
              //constructor1.setAccessible(true);
              
              
              
              
              
               //获取指定名称的方法
              Method eat_method = personClass.getMethod("eat");
              Person p = new Person();
              //执行方法
              eat_method.invoke(p);
      
      
              Method eat_method2 = personClass.getMethod("eat", String.class);
              //执行方法
              eat_method2.invoke(p,"饭");
      
              System.out.println("-----------------");
      
              //获取所有public修饰的方法
              Method[] methods = personClass.getMethods();
              for (Method method : methods) {
                  System.out.println(method);
                  String name = method.getName();
                  System.out.println(name);
                  //method.setAccessible(true);
              }
      
              //获取类名
              String className = personClass.getName();
              System.out.println(className);//com.test.Person
      
      
          }
      
      }
      

Invoke机制:

​ invoke() 是 Java 中的一个反射工具方法,用于调用指定方法,并传递相应的参数。该方法可以在程序运行时动态调用指定对象的方法,并执行相应的操作。

invoke() 方法的语法如下:

public Object invoke(Object obj, Object... args)
   throws IllegalAccessException, IllegalArgumentException, InvocationTargetException

其中,obj 参数是要调用方法的对象,args 参数是要传递给方法的参数列表,该方法返回一个 Object 类型的值,表示方法的返回值。

需要注意的是,使用 invoke() 方法调用方法时,需要注意方法的访问修饰符。如果要调用的方法是 private 或 protected 访问修饰符的,需要首先使用 setAccessible(true) 方法将其设置为可访问,否则将抛出 IllegalAccessException 异常。

下面是一个示例代码,演示如何使用 invoke() 方法调用指定对象的方法:

public class MyClass {
    public void doSomething(String arg1, int arg2) {
        // 执行某些操作
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        // 创建 MyClass 的实例
        MyClass myClass = new MyClass();
        // 获取 doSomething 方法的 Method   
        Method method = MyClass.class.getMethod("doSomething", String.class, int.class);
        // 调用 doSomething 方法
        method.invoke(myClass, "hello", 123);
    }
}

在上面的代码中,我们首先创建了 MyClass 的实例 myClass,然后使用 getMethod() 方法获取了 doSomething() 方法的 Method 对象 method。最后,我们使用 invoke() 方法调用了 doSomething() 方法,并传递了两个参数 “hello” 和 123。需要注意的是,doSomething() 方法必须是 public 访问修饰符的,否则会抛出 IllegalAccessException 异常。

实际案例:

pro.properties

className=cn.test.Student
methodName=sleep

Student.java

package com.test
public class Student {


    public void sleep(){
        System.out.println("sleep...");
    }
}

ReflectTest.java

public class ReflectTest {
    public static void main(String[] args) throws Exception {

		Properties properties = new Properties();
        Classloader classloader  = ReflectTest.class.getClassloader();
        InputStream is = classloader.getResourceAsStream("pro.properties");
        pro.load(is);
        
        // 获取配置文件中定义的数据;
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        
        // 获取到类的class对象
        Class class1 = Class.forName(className);
        // 创建对象并指定类的实例
        Obejct obj = class1.newInstance();
        // 获取方法的对象
        Method method1 = class1.getMethod();
        // 执行方法
        method1.invoke(obj);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值