浅聊Java反射
Java 的反射Reflection机制是 Java 语言中最强大、但也最容易让初学者感到迷惑的特性之一。如果用一句话概括反射它允许程序在运行期间Runtime像照镜子一样动态地获取任意一个类的内部结构包括属性、方法、构造器并且能够动态地操作这些属性和方法。为了让你由浅入深地理解我们分为四个阶段来拆解概念认知 - 获取“镜子” - 核心操作 - 底层意义。第一阶段为什么要用反射打破常规在正常情况下我们写代码是“正向”的。也就是先知道有什么类然后去new它调用它的方法。Java// 正向操作编译期就已经确定了 User user new User(); user.setName(张三); user.sayHello();但假设有一天你正在写一个框架比如 Spring。你不知道未来使用这个框架的程序员会写什么类你只知道他们会在一个配置文件比如 XML 文件里写下一串字符串classcom.example.User。这时候你没法在代码里写new User()因为你写框架的时候User类根本不存在反射就是为了解决这种“在运行时才确定要操作什么类”的问题。它赋予了 Java 极大的动态性。第二阶段拿到类的“解剖图” —— Class 对象在 Java 中万物皆对象。连“类”本身也是一种对象这种对象叫做Class对象。你想反射操作一个类第一步必须先拿到它的Class对象也就是它的解剖图。拿到Class对象有三种常见方式Java// 假设有一个现成的 User 类 // 方式一通过类名最常用适合硬编码 Class? clazz1 User.class; // 方式二通过实例对象知道对象想看看它属于什么类 User user new User(); Class? clazz2 user.getClass(); // 方式三通过类的全限定名字符串最动态框架最爱适合读取配置文件 Class? clazz3 Class.forName(com.example.User);拿到clazz之后你就可以对User类进行“解剖”了。第三阶段核心操作演练用代码说话为了演示我们先准备一个普通的User类注意里面有一些私有private的属性和方法。Javapublic class User { private String name; // 私有属性 public int age; // 无参构造 public User() { } // 带参构造 public User(String name, int age) { this.name name; this.age age; } // 私有方法 private void secretMethod() { System.out.println(name 的秘密方法被调用了); } // 公开方法 public void publicMethod() { System.out.println(大家好我是 name); } }接下来我们全程用反射来操作它就像黑客一样绕过常规限制。1. 动态创建对象不使用new关键字用反射实例化对象。JavaClass? clazz Class.forName(com.example.User); // 1. 调用无参构造创建对象 Object obj1 clazz.getDeclaredConstructor().newInstance(); // 2. 调用带参构造创建对象 Object obj2 clazz.getDeclaredConstructor(String.class, int.class) .newInstance(李四, 25);2. 暴力篡改私有属性反射的霸道之处正常情况下外界是无法修改private属性的但反射可以。JavaObject userObj clazz.getDeclaredConstructor().newInstance(); // 获取名为 name 的私有属性 Field nameField clazz.getDeclaredField(name); // 【核心魔术】打破封装允许访问私有成员 nameField.setAccessible(true); // 将 userObj 这个对象的 name 属性设置为 王五 nameField.set(userObj, 王五); // 验证一下 System.out.println(nameField.get(userObj)); // 输出: 王五3. 动态调用私有方法同样私有方法也能被强行调用。Java// 获取名为 secretMethod 的私有方法没有参数 Method secretMethod clazz.getDeclaredMethod(secretMethod); // 打破封装 secretMethod.setAccessible(true); // 执行 userObj 这个对象上的 secretMethod 方法 secretMethod.invoke(userObj); // 输出: 王五 的秘密方法被调用了第四阶段由深入浅看反射它的优缺点与应用场景看完了上面的代码你可能会觉得“这不仅麻烦破坏了面向对象的封装性private形同虚设而且每次都要抛出一大堆异常ClassNotFoundException,IllegalAccessException等。”为什么要用这么“危险”的东西应用场景无处不在的反射日常写业务代码增删改查你几乎永远用不到反射。但是一旦你开始接触或者编写底层框架反射就是灵魂Spring 框架 (IoC/DI)Spring 怎么知道给你注入哪个对象它就是通过读取 XML 或注解如Service,Autowired获取全类名然后通过反射Class.forName().newInstance()帮你把对象 new 出来并放进容器里的。JDBC 数据库连接Class.forName(com.mysql.cj.jdbc.Driver);这就是典型的反射加载驱动。MyBatis你只写了接口Mapper没有写实现类为什么能查数据库因为 MyBatis 在底层用反射和动态代理帮你动态生成了实现类。各种 JSON 序列化库如 Gson, FastJson它们怎么知道把你传进去的 JSON 字符串转成什么对象的也是通过反射读取对象的字段去赋值的。反射的“代价”性能开销反射是一种“解释性”操作Java 虚拟机无法对这类代码进行早期的性能优化。因此反射操作通常比直接的 Java 代码慢得多。不过在现代 JVM 中这种性能损耗在绝大多数常规业务场景下可以忽略不计。破坏安全性由于可以强制访问私有变量和方法可能会导致不可预知的副作用破坏了类的内部逻辑约束。总结一下反射就像是 Java 提供给开发者的一把“万能钥匙”和“X光机”。业务开发时把钥匙收好遵守面向对象规则框架开发时拿出钥匙追求极致的灵活性和解耦。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2613736.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!