Java反射,看完就会用

打印 上一主题 下一主题

主题 918|帖子 918|积分 2754

什么是反射

在说反射概念之前,我们先说另外2个概念:编译期运行期
编译期:

  • 编译期是源代码从文本形式转换为字节码的过程,这发生在Java代码被JVM执行之前。
  • 在编译期,编译器对源代码进行语法检查、类型检查、变量名解析等操作,确保代码符合Java的语法规则,并将其编译成字节码(.class文件)。
  • 编译期间的操作基于静态类型信息。编译器只能使用它在编译时了解的信息,而不能知晓运行时的具体情况。
运行期:

  • 运行期是指编译后的代码在Java虚拟机(JVM)上执行的过程。
  • 在运行期,JVM执行编译后的字节码,并进行各种运行时操作,如内存分配、垃圾回收等。
反射机制主要发生在运行期。反射允许程序在运行时动态访问和操作类、对象、方法、属性等。
使用反射,程序可以获取类的信息(如类名、方法、字段等),并可以创建对象、调用方法、修改字段值,这些都是在运行时发生的。
补充:在学习JVM内存结构时,我们知道在类信息是存放在方法区的。
反射的优缺点

优点:
在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点:
(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
反射的入口:Class类

类 Class 的实例代表在运行中的 Java 应用程序中的类和接口。枚举是一种类,注解是一种接口。每个数组也属于一个类,这个类以 Class 对象的形式反映出来,这个 Class 对象被所有具有相同元素类型和维数的数组共享。Java 的基本类型(boolean、byte、char、short、int、long、float 和 double)以及关键字 void 也表示为 Class 对象。
三种方式获取Class对象


  • 通过实例对象获取Class对象
  • 通过类名.class获取Class对象
  • 通过Class.forName(String className)获取Class对象
  1. @SpringBootTest
  2. class DemoReflectionApplicationTests {
  3.     @Test
  4.     void contextLoads() throws ClassNotFoundException {
  5.         User user = new User();
  6.         Class<? extends User> u1 = user.getClass();
  7.         System.out.println(u1.getName());
  8.         System.out.println(u1.hashCode());
  9.         Class<User> u2 = User.class;
  10.         System.out.println(u2.hashCode());
  11.         Class<?> u3 = Class.forName("com.example.reflection.pojo.User");
  12.         System.out.println(u3.hashCode());
  13.     }
  14. }
复制代码
  1. com.example.reflection.pojo.User
  2. 1970707120
  3. 1970707120
  4. 1970707120
复制代码
在运行期间,一个类只有一个Class对象产生。
获取到Class对象,我们能拿到哪些信息?

获取名称信息
  1. // 返回Java内部使用的真正的名称
  2. public String getName();
  3. // 返回的名称不带包信息
  4. public String getSimpleName();
  5. // 返回的名称更加友好
  6. public String getCanonicalName();
  7. // 返回包信息
  8. public String getPackage();
复制代码
  1. @Test
  2. void contextLoad2() throws ClassNotFoundException {
  3.     Class<?> u = Class.forName("com.example.reflection.pojo.User");
  4.     System.out.println(u.getName());
  5.     System.out.println(u.getSimpleName());
  6.     System.out.println(u.getCanonicalName());
  7.     System.out.println(u.getPackage());
  8.     Class<String> s = String.class;
  9.     System.out.println(s.getName());
  10.     System.out.println(s.getSimpleName());
  11.     System.out.println(s.getCanonicalName());
  12.     System.out.println(s.getPackage());
  13. }
复制代码
结果:
  1. com.example.reflection.pojo.User
  2. User
  3. com.example.reflection.pojo.User
  4. package com.example.reflection.pojo
  5. java.lang.String
  6. String
  7. java.lang.String
  8. package java.lang, Java Platform API Specification, version 1.8
复制代码

获取字段信息

Class获取字段信息的方法:
  1. // 返回所有的public字段,包括其父类的,如果没有字段,返回空数组
  2. public Field[] getFields()
  3. // 返回本类声明的所有字段,包括非public的,但不包括父类的
  4. public Field[] getDeclaredFields()
  5. // 返回本类或父类中指定名称的public字段,找不到抛出异常NoSuchFieldException
  6. public Field getField(String name)
  7. // 返回本类中声明的指定名称的字段,找不到抛出异常NoSuchFieldException
  8. public Field getDeclaredField(String name)
复制代码
获取到Field以后,进一步获取字段信息:
[code]// 获取字段的名称public String getName()// 判断当前程序是否有该字段的访问权限public boolean isAccessible()// flag设为true表示忽略Java的访问检查机制,以允许读写非public的字段public void setAccessible(boolean flag)// 获取指定对象obj中该字段的值public Object get(Object obj)// 将指定对象obj中该字段的值设为valuepublic void set(Object obj, Object value)// 返回字段的修饰符public int getModifiers()//返回字段的类型public Class

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

圆咕噜咕噜

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表