1.类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
加载
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。
连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值 static{}语句块
解析 将类的二进制数据中的符号引用替换为直接引用
初始化类型
创建类的实例
访问类的静态变量,或者为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
2.类加载器
负责将.class文件加载到内在中,并为之生成对应的Class对象。
3.类加载器的组成
Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
自己写的类使用此加载器执行
4.反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
反射代码详细解析:
测试类
package com.xiaoqiang;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class StudentReflex {
// 获取Class类对象的三种方法
@Test
public void test1() throws Exception {
Class c1 = Student.class;
Class c2 = new Student().getClass();
Class c3 = Class.forName("com.xiaoqiang.Student");
System.out.println(c1.equals(c2));// true
System.out.println(c1.equals(c3));// true
/*
* 推荐使用第三种,可以遵循避开原则, 将字符串存储在配置文件中 读取配置文件
*/
}
// 构造方法获取及使用
@Test
public void test2() throws Exception {
Class c = Class.forName("com.xiaoqiang.Student");
Constructor[] cons1 = c.getConstructors();
// 获取所有公有构造方法
for (Constructor constructor : cons1) {
System.out.println(constructor);
}
Constructor[] cons = c.getDeclaredConstructors();
// 获取所有构造方法
for (Constructor constructor : cons) {
System.out.println(constructor);
}
// 通过反射调用私有构造方法
Constructor con = c.getDeclaredConstructor(String.class, String.class);
// 若调用非公有的构造方法需要设置安全管理器
con.setAccessible(true);
Object obj = con.newInstance("小强", "男");
System.out.println(obj);
}
//属性的获取及设置
@Test
public void test3() throws Exception {
Class c = Class.forName("com.xiaoqiang.Student");
Object obj = c.newInstance();
Field[] fields1 = c.getFields();
//获取公有的属性
for (Field field : fields1) {
System.out.println(field);
}
Field[] fields = c.getDeclaredFields();
//获取所有属性
for (Field field : fields) {
System.out.println(field);
}
//加上 Declared 可访问私有属性
Field fieldName = c.getDeclaredField("name");
Field fieldSex = c.getDeclaredField("sex");
Field fieldAge = c.getDeclaredField("age");
fieldName.set(obj, "小强");
fieldSex.set(obj, "男");
fieldAge.setAccessible(true);
//设置安全管理器强制访问
fieldAge.set(obj, 18);
System.out.println(obj);
}
//方法获取及使用
@Test
public void test4() throws Exception {
Class c = Class.forName("com.xiaoqiang.Student");
Object obj = c.newInstance();
Method[] methods1 = c.getMethods();
//获取所有公有方法 (包括继承过来的) 所有类继承自 Object
for (Method method : methods1) {
System.out.println(method);
}
Method[] methods = c.getDeclaredMethods();
//获取本类所有方法 (不包括继承的) 包括非私有,保护,和默认
for (Method method : methods) {
System.out.println(method);
}
Method method = c.getDeclaredMethod("eat", null);
// 此处null为参数 类型为Class类型
method.setAccessible(true);
//设置安全管理器强制访问 私有方法
method.invoke(obj, null);
// null 位置若有参数 直接传递
}
}
学生类
package com.xiaoqiang;
public class Student {
public String name;
protected String sex;
private int age;
public Student() {
}
private Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
protected Student(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public void study(){
System.out.println("学习ing");
}
private void eat(){
System.out.println("吃ing");
}
@Override
public String toString() {
return "Student [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
下期预告
下次博客将讲解apache的开源框架commons-beanutils,通过反射机制实现
该框架广泛用于其他框架中如struts,hibernate,spring中。