zoukankan      html  css  js  c++  java
  • 反射--解刨一个类的艺术

    反射的艺术:

      概念类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。

    字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中万物皆对象,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。

      通过Class类、Method类、Field类等等类可以得到这个类型的一些信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术

      --Class类:

      获取Class类的三种方式:

        Java中有一个Class类用于代表某一个类被jvm编译后的字节码。

    •  forName().forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装  推荐使用,后端很多封装框架都利用此原理+代理模式封装
    •    类名.Class();
    •  对象.getClass(); 
      package com.kk.reflect;
      
      public class Person {
          private String name;
          private Integer age;
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
          public Integer getAge() {
              return age;
          }
          public void setAge(Integer age) {
              this.age = age;
          }
          
          public Person(String name, Integer age) {
              super();
              this.name = name;
              this.age = age;
          }
          public Person() {
              super();
              // TODO Auto-generated constructor stub
          }
        public void eat(){
              System.out.println("eat doing........");
          }
      
        public void eat(String hello){
              System.out.println("eat doing........"+hello);
              
        }
        public static void  play(){
              System.out.println("play static doing........");
          }
        private void movie(String name){
              System.out.println("movie private doing........"+name);
          }
          public String publicId;
          public String publicType;
          
          
          public String getPublicType() {
              return publicType;
          }
          public void setPublicType(String publicType) {
              this.publicType = publicType;
          }
          public String getPublicId() {
              return publicId;
          }
          public void setPublicId(String publicId) {
              this.publicId = publicId;
          } }
      /**
           * 加载类的字节码的3种方式
           * @throws Exception
           * */
          public void test1() throws Exception {
              // 方式一
              Class clazz1 = Class.forName("cn.kk.reflect.Person");
              // 方式二
              Class clazz2 = Person.class;
              // 方式三
              Person p1 = new Person();
              Class clazz3 = p1.getClass();
          }

      通过Class类获取类型的信息:

    • getName()类的名称(全名,全路径名)
    • getSimpleName()类的的简单名称(不带包名)
    • getModifiers(); 类的的修饰符
    • newInstance()//创建对象无参数构造创建对象
    • Constructor<T> getConstructor(Class<?>... parameterTypes)//获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例
      /**
           * 通过Class对象获取类的一些信息
           * 
           * @throws Exception
           * */
          private static void test2() throws Exception {
      
              Class clazz1 = Class.forName("cn.kk.reflect.Person");
              // 获取类的名称
              String name = clazz1.getName();
              System.out.println(name); //cn.kk.reflect.Person
              // 获取类的简单名称
              System.out.println(clazz1.getSimpleName()); // Person
              // 获取类的修饰符
              int modifiers = clazz1.getModifiers();
              System.out.println(modifiers);
              // 构建对象(默认调用无参数构造.)
              Object ins = clazz1.newInstance();
              Person p = (Person) ins;
              System.out.println(p); //cn.kk.reflect.Person@15db9742
              // 获取指定参数的构造函数
              Constructor<?> con = clazz1.getConstructor(String.class, Integer.class);
              // 使用Constructor创建对象.
              Object p1 = con.newInstance("jack", 28);
              System.out.println(((Person) p1).getName());
          }

      通过Class类获取类型的信息:

    • 获取公共方法包括继承父类的方法    getMethods()返回一个数组,元素类型是Method;
    • 获取指定参数的公共方法         getMethod("setName", String.class);
    • 获得所有的方法,包括私有        Method[] getDeclaredMethods();
    • 获得指定参数的方法,包括私有      Method getDeclaredMethod(String name, Class<?>... parameterTypes);
    1. /**

       * 获取公有方法.

       * @throws Exception

       * */

      private static void test3() throws Exception {

          Class clazz1 = Class.forName("com.kk.reflect.Person");
          // 1.获取非私用方法(包括父类继承的方法)
          Method[] methods = clazz1.getMethods();
          System.out.println(methods.length);
          for (Method m : methods) {
               System.out.println(m.getName());
              if ("eat".equals(m.getName())) {
                  //Method的invoke()方法的使用
                  m.invoke(clazz1.newInstance(), null);
              }
          }
          }
      /**
           * 获取指定方法签名的方法
           * 
           * @throws Exception
           * */
          private static void test4() throws Exception {
              Class clazz1 = Class.forName("com.kk.reflect.Person");
              // 获取指定名称的函数
              Method method1 = clazz1.getMethod("eat", null);
              method1.invoke(new Person(), null);
          }
      /**
           * 获取指定方法名且有参数的方法
           * 
           * @throws Exception
           * */
          private static void test5() throws Exception {
                  /**
           * public void eat(String hello){
              System.out.println("eat doing........"+hello);
              }
           */
          Class clazz1 = Class.forName("com.kk.reflect.Person");
          Method method = clazz1.getMethod("eat",String.class);
          method.invoke(new Person(), "joker");
          }
          }
          /**
           * 获取指定方法名,参数列表为空的方法.
           * 
           * @throws Exception
           * */
          private static void test4() throws Exception {
               /**
               * public void eat(){
              System.out.println("eat doing........");
              }
               */
              Class clazz1 = Class.forName("com.kk.reflect.Person");
              // 获取指定名称的函数
              Method method1 = clazz1.getMethod("eat", null);
              method1.invoke(new Person(), null);
              
          }
      /**
           * 反射静态方法
           * @throws Exception
           * */
          private static void test7() throws Exception {
                  /**
               * public static void  play(){
                      System.out.println("play static doing........");
                  }
               */
              Class clazz1 = Class.forName("com.kk.reflect.Person");
              
              Method method = clazz1.getMethod("play", null);
              method.invoke(null, null);
          }
          /**
           * 访问私有方法 暴力反射
           * @throws Exception
           * */
          private static void test6() throws Exception {
          /**
               * private void movie(String name){
                  System.out.println("movie private doing........"+name);
                  }
               */
              Class clazz1 = Class.forName("com.kk.reflect.Person");
              Method method = clazz1.getDeclaredMethod("movie", String.class);
              method.setAccessible(true);
              method.invoke(new Person(), "苍老师");
          }

      通过Class类获取类型中的字段的信息

    • 获取公共字段               Field[] getFields()
    • 获取指定参数的公共字段          Field getField(String name)
    • 获取所有的字段              Field[] getDeclaredFields() 
    • 获取指定参数的字段,包括私用       Field getDeclaredField(String name)
      /**
           * 获取公有的字段  实体类中添加共有属性级getsetter方法     public String publicId;     public String publicType;
           * */
          private static void test8() throws Exception {
              Person p = new Person();
              Class clazz1 = Class.forName("com.kk.reflect.Person");
              //获取公共字段
              Field[] fields = clazz1.getFields();
              System.out.println(fields.length);
              for (Field f : fields) {
                  System.out.println(f.getName());
                  if ("publicId".equals(f.getName())) {
                      System.out.println(f.getType().getName());
                      f.set(p, "1922");
                  }
                  if ("publicType".equals(f.getName())) {
                      System.out.println(f.getType().getName());
                      f.set(p, "typeZS");
                  }
              }
              System.out.println(p.getPublicId());
              System.out.println(p.getPublicType());
          }
      
      /**
           * 获取私有的字段
           * @throws Exception
           * */
          private static void test9() throws Exception {
              Person p = new Person();
              Class clazz1 = Class.forName("com.kk.reflect.Person");
              Field field = clazz1.getDeclaredField("age");
              System.out.println(field.getName());
         //私有方法不能直接访问,因为权限不够。非要访问,可以通过暴力的方式 field.setAccessible(
      true);//一般很少用,因为私有就是隐藏起来,所以尽量不要访问。 field.set(p, 100); System.out.println(p.getAge()); } }

      补充Method的invoke()方法的使用

    • 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。
    • 如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
    • 如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
    • 如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。
    • 如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。
    • obj - 从中调用底层方法的对象(简单的说就是调用谁的方法用谁的对象)args - 用于方法调用的参数

      总结:对反射理解深入有利于对后端底层框架的深入了解,及源码分析,会让你明白java框架底层到底是怎么一回事,所以挺总要的,本文简单总结了一下知识点,言简意赅,不足之处望多指教。

    • 2018年1月28日 星期天,我在西安,好多年没下过这么大的雪,在家写写博客记录下知识,希望能帮助到同我一样向往着诗和远方朋友!
  • 相关阅读:
    RabbitMQ学习总结(5)——发布和订阅实例详解
    RabbitMQ学习总结(4)——分发任务在多个工作者之间实例教程
    RabbitMQ学习总结(4)——分发任务在多个工作者之间实例教程
    RabbitMQ学习总结(3)——入门实例教程详解
    RabbitMQ学习总结(3)——入门实例教程详解
    RabbitMQ学习总结(2)——安装、配置与监控
    RabbitMQ学习总结(2)——安装、配置与监控
    ActiveMQ学习总结(4)——业界消息队列简介
    ActiveMQ学习总结(4)——业界消息队列简介
    华为云ModelArts图深度学习,学习知识还能考取微认证
  • 原文地址:https://www.cnblogs.com/douyu2580860/p/8359313.html
Copyright © 2011-2022 走看看