Java Reflect 反射机制

Java Reflect 反射机制

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

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

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

  1. Class类
    1. 获取Class对象的三种方式
      Java中有一个Class类用于代表某一个类的字节码。

      1. Java提供了三种方式获取类的字节码
        1. Class.forName("")方法用于加载某个类的字节码到内存中,并使用class对象进行封装
        2. 类名.class
        3. 对象.getClass()
        /**
         * 加载类的字节码的3种方式
         * @throws ClassNotFoundException
         */
        @Test
        public void test() throws ClassNotFoundException {
            // 方式一
            Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
            // 方式二
            Class clazz2 = Person.class;
        
            // JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,
            // 而是直接使用之前缓存的这个字节码信息。
            // clazz1 == clazz2 : true
            System.out.println("clazz1 == clazz2 : " + (clazz1 == clazz2));
        
            // 方式三
            Person p1 = new Person();
            Class clazz3 = p1.getClass();
        
            System.out.println("clazz3 == clazz2 : " + (clazz3 == clazz2));
        }
        
    2. 通过Class类获取类型的一些信息

      1. getName()类的名称(全名,全限定名)
      2. getSimpleName()类的的简单名称(不带包名)
      3. getModifiers(); 类的的修饰符
      4. 创建对象 无参数构造创建对象 newInstance()
      5. 获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例 Constructor<T> getConstructor(Class<?>... parameterTypes)
      /**
       * 通过Class对象获取类的一些信息
       * @throws Exception
       */
      @Test
      public void test2() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          // 获取类的名称
          String name = clazz1.getName();
          System.out.println(name);
          // 获取类的简单名称
          System.out.println(clazz1.getSimpleName()); // Person
          // 获取类的修饰符
          int modifiers = clazz1.getModifiers();
          System.out.println(modifiers);
      
          // 通过class对象找到所有的构造方法
          Constructor[] constructors = clazz1.getConstructors();
          for( Constructor constructor : constructors){
              System.out.println("    " + constructor);
          }
      
          // 通过class对象找到所有的构造方法,包括私有方法
          Constructor[] declaredConstructors = clazz1.getDeclaredConstructors();
          for( Constructor constructor : declaredConstructors){
              System.out.println("    " + constructor);
          }
      
          // 构建对象(默认调用无参数构造.)
          Object ins = clazz1.newInstance();
          Person p = (Person) ins;
          System.out.println(p);
          // 获取指定参数的构造函数
          Constructor<?> con = clazz1.getConstructor(String.class, int.class);
          // 使用Constructor创建对象.
          Object p1 = con.newInstance("jack", 12);
          System.out.println(((Person) p1).getName());
      
          // 通过私有构造方法创建对象
          Constructor constructor = clazz1.getDeclaredConstructor(String.class, int.class, int.class);
          // 设置构造方法的访问权限(暴力反射)
          constructor.setAccessible(true);
          Person p2 = (Person) constructor.newInstance("jj", 20, 1);
          System.out.println("p2.name = " + p2.getName());
      }
      
    3. 通过Class类获取类型中的方法的信息
      1.获取公共方法包括继承的父类的方法 getMethods()返回一个数组,元素类型是Method
      2.获取指定参数的公共方法 getMethod("setName", String.class);
      3.获得所有的方法,包括私有 Method[] getDeclaredMethods()
      4.获得指定参数的方法,包括私有 Method getDeclaredMethod(String name, Class<?>... parameterTypes)

      /**
       * 获取公有方法.
       * @throws Exception
       */
      @Test
      public void test3() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.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())) {
                  m.invoke(clazz1.newInstance(), null);
              }
              System.out.println("    " + m.getName());
          }
      }
      
      /**
       * 获取指定方法签名的方法
       *
       * @throws Exception
       */
      public void test4() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          // 获取指定名称的函数
          // 第一个参数是方法名, 第二个参数是形参列表的数据类型
          Method method1 = clazz1.getMethod("toString", null);
          // 执行方法
          // 第一个参数: 方法的调用者(对象),第二个参数: 方法执行的第二个参数
          method1.invoke(new Person(), null);
      }
      
      /**
       * 获取指定方法名且有参数的方法
       *
       * @throws Exception
       */
      @Test
      public void test5() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Method method = clazz1.getMethod("setName", String.class);
          method.invoke(new Person(), "包子");
      }
      
      /**
       * 获取指定方法名,参数列表为空的方法.
       *
       * @throws Exception
       */
      @Test
      public void test6() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          // 获取指定名称的函数
          Method method1 = clazz1.getMethod("sayHello", null);
          method1.invoke(new Person(), null);
      }
      
      /**
       * 反射静态方法
       * @throws Exception
       */
      @Test
      public void test8() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Method method = clazz1.getMethod("sayHi", null);
          method.invoke(null, null);
      }
      
    4. 通过Class类获取类型中的字段的信息

      1. 获取公共字段 Field[] getFields()
      2. 获取指定参数的公共字段 Field getField(String name)
      3. 获取所有的字段 Field[] getDeclaredFields()
      4. 获取指定参数的字段,包括私用 Field getDeclaredField(String name)
      /**
       * 获取公有的字段
       */
      @Test
      public void test9() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Field[] fields = clazz1.getFields();
          Person p = new Person();
          System.out.println(fields.length);
          for (Field f : fields) {
              System.out.println(f.getName());
              if ("name".equals(f.getName())) {
                  System.out.println(f.getType().getName());
                  f.set(p, "jack");
              }
          }
          System.out.println(p.getName());
      }
      
      /**
       * 获取私有的字段
       * @throws Exception
       */
      @Test
      public void test10() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Field field = clazz1.getDeclaredField("age");
          System.out.println(field.getName());
          field.setAccessible(true);
          Person p = new Person();
          field.set(p, 100);
          System.out.println(p.getAge());
      }
      
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,531评论 18 399
  • 学习Android的同学注意了!!!学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Android学习交流群...
    kingZXY2009阅读 330评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,561评论 18 139
  • 《写给十年后的自己》 亲爱的自己,你好,见字如面! 十年后的你会变成什么样呢,我很期待,一大早去楼下等你,我知道每...
    霜霜_b33a阅读 378评论 0 0
  • 周末有一项作业,语文老师用心良苦,让孩子们写一篇五十字的读后感,传在班级QQ群里。我知道儿子是不看书的,那么这...
    ganweif阅读 165评论 0 0