前言
反射是被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类得内部信息,并能够直接操作任意对象得内部属性和方法(包括私有)。
加载完类之后,在方法区中就会产生一个Class类型对象,这个对象就包含了完整得类得结构信息。我们可以通过这个对象看到类得结构。这个对象就像就像一面镜子,透过这个镜子可以看到类得结构,所以,我们形象得称之为:反射。
所以我们首先简单的讲一下类加载,然后在讲反射机制。
类加载
类加载步骤
分为三步:加载、链接、初始化
加载Loading
作用:在内存中生成一个代表这个类的Class对象,作为方法区中这和类的各种数据的访问入口。
什么时候加载?
- new
- Class.forName(“包名。类名”)
怎么加载?
Bootstrap(根加载器,加载$JAVA_HOME/jre/lib/rt.jar包内的class文件,包含java运行环境所需的基础类)
ExtClass(加载$JAVA_HOME/jre/lib/ext/.jar目录下的class文件)
AppClass(用于——加载当前应用的classpath的所有类)
链接 Linking
该过程分三个阶段:验证、准备、解析
验证:验证阶段用于确保加载的Class文件的字节流包含的信息是否符合虚拟机要求,保证其合法性。
准备阶段: 为类变量(静态变量)分配内存并跟根据对象类型赋对应的默认值。
解析阶段:用于将符号引用转换为直接引用。
初始化 initialization
执行类的构造方法的过程
反射技术
运行时动态访问对象的属性和方法。
Class对象
上面我们简单的了解了以下类加载机制。
那我们如何得到Class对象呢?
通常我们又三种方法:
第一种,使用 Class.forName 静态方法。 前提:已明确类的全路径名。
第二种,使用 .class 方法。 说明:仅适合在编译前就已经明确要操作的 Class
第三种,使用类对象的 getClass() 方法。 适合有对象示例的情况下
代码:
package com.dyit.clazz;
public class GetClass {
//定义一个内部类
static class A {
public A() {
}
public void print() {
System.out.println("内部类");
}
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
//得到class对象
System.out.println(A.class);
A b = new A();
System.out.println(b.getClass());
System.out.println(Class.forName("com.dyit.clazz.GetClass$A"));
}
}
结果截图:
那我们拿到Class对象可以干什么呢?
之前我们类的实例化有三种方式:
new 关键字
克隆
反序列化
现在我们可以通过类的Class对象创建类的实例
通过Class.newInstance()可以得到类的实例;
可以通过Class.getSimpleName()得到类的名称
代码如下:
package com.dyit.clazz;
public class ClassDemo {
//定义一个内部类
static class A {
public A() {
}
public void print() {
System.out.println("内部类");
}
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//得到Class对象
Class<A> a = A.class;
//得到类的名称
System.out.println(a.getName());
System.out.println(a.getSimpleName());
//创建实例
A b = a.newInstance();
//调用方法
b.print();
}
}
结果:
Field类
描述类中的属性,(数值)域
首先通过Class对象得到所有的属性
Class.getDeclaredFields()
通过设置field.setAccessible(true)可以访问私有属性。
field.get(c) 得到c关于这和属性的值
field.getName()得到属性的名称
field.getType()得到属性的类型
field.getType()。getSimpleName()得到属性的简单名称
可以通过set方法设置对象属性的值:field.set(c, 999.99)
|