Java反射机制原来没有那么难

Java反射机制原来没有那么难
前言
 
反射是被视为动态语言的关键,反射机制允许程序在执行期间借助于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)

推荐阅读