类加载
类在内存中的声明周期
- 加载 -> 使用 -> 卸载
类加载的三个阶段
类初始化
会导致类初始化的操作
- 运行主方法所在的类
- 第一次new对象的时候
- 调用某个类的静态成员
- 子类初始化时,如果父类还没有初始化,那么先初始化父类
- 通过反射操作某个类时,如果这个类没有初始化,也会导致该类的初始化
不会导致类初始化的操作
- 使用某个类的静态常量 static final
- 通过子类调用父类的静态变量、静态方法,只会导致父类初始化,不会导致子类初始化
- 用某个类型声明数组并创建数组对象时,不会导致这个类初始化
类加载器
类加载器的分类
- 引导类加载器
- 扩展类加载器
- 应用程序类加载器
- 自定义加载器
双亲委托模式
- 下一级的类加载器,如果接到任务时,会先搜索是否加载过,如果没有,会先把任务往上传,如果都没有加载过,一直到根加载器,如果根加载器在它负责的路径下没有找到,会往回传,如果一路回传到最后一级都没有找到,那么会报ClassNotFoundException或NoClassDefError,如果在某一级找到了,就直接返回Class对象
获取Class对象的四种方式
哪些类型可以获取Class对象
- 所有类型
方式1
- 类型名.class
方式2
- 对象.getClass()
方式3
- Class.forName(类型全名称)
方式4
ClassLoader的类加载器对象.loadClass(类型全名称)
public class TestClass { @Test public void test05() throws ClassNotFoundException{ Class c = TestClass.class; ClassLoader loader = c.getClassLoader(); Class c2 = loader.loadClass("com.atguigu.test05.Employee"); Class c3 = Employee.class; System.out.println(c2 == c3); } @Test public void test03() throws ClassNotFoundException{ Class c2 = String.class; Class c1 = "".getClass(); Class c3 = Class.forName("java.lang.String"); System.out.println(c1 == c2); System.out.println(c1 == c3); } }
反射的应用
获取类型的详细信息
创建任意引用类型的对象
@Test
public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
// AtGuigu obj = new AtGuigu();//编译期间无法创建
Class<?> clazz = Class.forName("com.atguigu.test.AtGuigu");
//clazz代表com.atguigu.test.AtGuigu类型
//clazz.newInstance()创建的就是AtGuigu的对象
Object obj = clazz.newInstance();
System.out.println(obj);
}
操作任意类型的属性
public class TestField {
public static void main(String[] args)throws Exception {
//1、获取Student的Class对象
Class clazz = Class.forName("com.atguigu.test.Student");
//2、获取属性对象,例如:id属性
Field idField = clazz.getDeclaredField("id");
//3、如果id是私有的等在当前类中不可访问access的,我们需要做如下操作
idField.setAccessible(true);
//4、创建实例对象,即,创建Student对象
Object stu = clazz.newInstance();
//5、获取属性值
/*
* 以前:int 变量= 学生对象.getId()
* 现在:Object id属性对象.get(学生对象)
*/
Object value = idField.get(stu);
System.out.println("id = "+ value);
//6、设置属性值
/*
* 以前:学生对象.setId(值)
* 现在:id属性对象.set(学生对象,值)
*/
idField.set(stu, 2);
value = idField.get(stu);
System.out.println("id = "+ value);
}
}
调用任意类型的方法
public class TestMethod {
@Test
public void test()throws Exception {
// 1、获取Student的Class对象
Class<?> clazz = Class.forName("com.atguigu.test.Student");
//2、获取方法对象
/*
* 在一个类中,唯一定位到一个方法,需要:(1)方法名(2)形参列表,因为方法可能重载
*
* 例如:void setName(String name)
*/
Method method = clazz.getDeclaredMethod("setName", String.class);
//3、创建实例对象
Object stu = clazz.newInstance();
//4、调用方法
/*
* 以前:学生对象.setName(值)
* 现在:方法对象.invoke(学生对象,值)
*/
method.invoke(stu, "张三");
System.out.println(stu);
}
}