1. Java反射机制概述
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期间借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性和方法
加载完类之后,在堆内存的方法区中就产生了一个Class类的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子可以看到类的内部结构,因此,我们形象的称之为:反射.
注意,Java不是动态语言,它和C++一样是静态语言。但是Java有一定的动态性,被称为“准静态语言”。我们可以利用反射机制、字节码操作来获得类似动态语言的特性。
【反射机制提供的一些功能】
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
2. 反射的强大
一个类的外部不可以调用该类的私有结构,但是反射可以!反射可以随意调用一个类的私有构造器、私有属性、私有方法。
Person类: ```java package pkg15;
public class Person { // 私有属性 private String name; // 私有方法 private String getName(){ return name ; } // 私有构造器 private Person(String name) { this.name = name; }
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
通过反射调用Person的私有结构:
```java
package pkg15;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
Class cla = Person.class; // 创建Class类的实例
// 调用私有构造器
Constructor constructor = cla.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object p = constructor.newInstance("zhangsan");
System.out.println(p.toString());
// 调用私有属性
Field name = cla.getDeclaredField("name") ; // 传入属性名
name.setAccessible(true);
System.out.println(name);
name.set(p,"lisi");
System.out.println(p);
// 调用私有方法
Method getName = cla.getDeclaredMethod("getName");// 传入方法名和入参类型
getName.setAccessible(true);
Object invoke = getName.invoke(p);// invoke 指调用,p指定调用方法的对象
System.out.println(invoke);
}
}
反射调用私有方法可以来感受一下,原来正常是对象调用方法,现在变成了方法调用对象。
3. Class类的理解
- 类的加载过程:
- 程序经过编译(javac)命令以后,会生成一个或多个字节码文件,接着我们使用运行(java)命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,此过程就成为加载。加载到内存中的类就成为了运行时类,此运行类就作为Class的一个实例。可以理解为:类运行时本身就是个对象(Java万物皆对象)
- 换句话说,Class的实例就对应一个运行时类。言外之意,Class的实例无法被手动new出来
- 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类