零、类的加载时机&类加载器
1.类的加载时机
当程序要使用某个类时,如果该类还未被加载到内存中,系统会通过加载,连接,初始化三步来实现对这个类进行初始化。其中加载 就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。连接分为两步①验证 是否有正确的内部结构,并和其他类协调一致②准备 负责为类的静态成员分配内存,并设置默认初始化值。初始化是指初始化成员变量等等。
总的来说类的加载时机分为以下几种:
- 创建类的实例
- 访问类的静态变量,或者为静态变量赋值
- 调用类的静态方法
- 初始化某个类的子类
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
2.类加载器
1.什么是类加载器
类加载器(classloader)主要是负责将.class文件加载到内存中,并为之生成对应的Class对象的一种机制。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
2. 类加载器分类
类别 | 作用 |
---|---|
根类加载器 | 也被称为引导类加载器,负责Java核心类的加载 比如System,String等。在JDK中JRE的lib目录下rt.jar文件中 |
扩展类加载器 | 负责JRE的扩展目录中jar包的加载。 在JDK中JRE的lib目录下ext目录 |
系统类加载器 | 负责在JVM启动时加载来自java命令的class文件 以及classpath环境变量所指定的jar包和类路径 |
一、反射
我们首先知道创建一个对象的三个阶段分为:
- 源文件阶段 .java的文件
- 字节码阶段 .class
- 创建对象阶段 new 对象名称
那么什么是反射呢?JAVA反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态用对象的方法的功能称为java语言的反射机制。想要使用反射,就必须得要获取字节码文件。
假设我们有如下一个Person类,我们通过字节码去获取这个类的属性、方法、对象等
public class Person {
public String name;
public int age;
private String gender;
public Person() {
super();
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public void show() {
System.out.println("姓名 "+ name + "年龄 " + age);
}
private void eat(String g) {
gender = g;
System.out.println("性别"+gender);
}
}
1.获取字节码对象
获取字节码对象有三种方法:
- Object类的getClass()方法,判断两个对象是否是同一个字节码文件
- 静态属性class,当作静态方法的锁对象
- Class类中静态方法forName(),读取配置文件
public static void main(String[] args) throws Exception {
//方法1
Class clazz = Class.forName("com.thinmoon.reflect.Person");
//方法2
Class clazz2 = Person.class;
//方法3
Person p = new Person();
Class clazz3 = p.getClass();
}
2.通过字节码创建对象
1).通过无参构造创建对象
//1.
Class clazz = Class.forName("com.thinmoon.reflect.Person");
Person p = (Person)clazz.newInstance();
p.age = 1;
p.name = "ls";
p.show();
2).通过有参构造创建对象
//2.
Class clazz = Class.forName("com.thinmoon.reflect.Person");
//获取构造器
Constructor c = clazz.getConstructor(String.class, Integer.class);
//通过构造器创建对象
Person p2 = (Person)c.newInstance("lsss", 111);
p2.show();
3.获取字段
1).获取公共字段
//获取公有属性
Field f = clazz.getField("name");
f.set(p2, "ssss");
2).获取私有属性
//获取私有属性
Field f1 = clazz.getDeclaredField("gender");
//去除私有权限
f1.setAccessible(true);
f1.set(p2, "女");
4.获取方法
1).获取公共方法
//获取公共方法
Method m1 = clazz.getMethod("show");
m1.invoke(p2);
2).获取私有方法
//获取私有方法
Method m2 = clazz.getDeclaredMethod("eat", String.class);
m2.setAccessible(true);
m2.invoke(p2, "sssaaaaaaaaa");