Java反射是Java语言的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。通过反射,我们可以获取类的信息(如类名、方法、字段),以及在运行时动态创建对象和调用方法。以下是对Java反射的详细总结:
1. **获取类的完整信息**
在示例中,`demo.getClass().getName()` 返回了对象 `demo` 所属类的完整包名和类名。所有Java类的对象都隐含地持有一个 `Class` 对象,它代表了这个对象的类型。`Class` 类提供了获取类信息的各种方法,如 `getName()` 返回类的全名(包括包名)。
2. **实例化 `Class` 对象**
- `Class.forName("Reflect.Demo")`: 这种方式通过类的全名动态加载并返回 `Class` 对象。如果类不存在,会抛出 `ClassNotFoundException`。
- `new Demo().getClass()`: 直接创建对象 `Demo`,然后调用 `getClass()` 方法获取 `Class` 对象。
- `Demo.class`: 类名后跟 `.class` 是静态语法,直接得到对应的 `Class` 对象,无需实例化。
3. **通过 `Class` 实例创建对象**
- `newInstance()` 方法:如果类有无参构造器,可以通过 `newInstance()` 创建该类的新实例。如果有参数的构造器,或者没有公共的无参构造器,将会抛出 `InstantiationException` 和 `IllegalAccessException`。在示例中,当Person类没有无参构造器时,调用 `newInstance()` 会报错。
4. **访问类的成员**
- `getDeclaredMethods()`: 获取类的所有声明的方法(包括私有的)。
- `getMethods()`: 获取类的公共方法(包括继承的)。
- `getConstructors()`: 获取类的所有构造器。
- `getField()`, `getDeclaredField()`: 获取类的字段,`getDeclaredField()` 包括私有的。
5. **调用方法和设置/获取字段值**
- `Method method = clazz.getDeclaredMethod("methodName", parameterTypes...)`: 获取指定方法。
- `method.invoke(object, parameters...)`: 调用方法,`object` 是目标对象,`parameters` 是传递给方法的参数。
- `Field field = clazz.getDeclaredField("fieldName")`: 获取字段。
- `field.set(object, value)`: 设置字段值。
- `field.get(object)`: 获取字段值。
6. **安全性与性能**
反射虽然强大,但也存在安全风险,因为它可以访问私有成员,这可能破坏封装性。此外,反射操作通常比直接调用方法或访问字段慢,因为它涉及到运行时的动态查找和访问。
7. **应用场景**
- 插件机制:在不修改源代码的情况下,加载和使用插件。
- 框架设计:Spring、Hibernate等框架广泛使用反射实现动态代理、依赖注入。
- 测试工具:JUnit等测试框架利用反射来测试私有方法或构造器。
- 数据库持久化:ORM框架通过反射将对象映射到数据库记录。
总之,Java反射提供了一种灵活的方式来处理运行时的类信息,允许我们动态地操作类和对象,但同时也需要注意其潜在的安全性和性能问题。在实际开发中,应谨慎使用反射,特别是在性能敏感的场景下。