类加载器
类加载内存分析
public class Test04 {
public static void main(String[] args) {
A a = new A();
System.out.println(a.a);//20
}
}
class A{
//第一个执行
static {
System.out.println("静态代码块初始化");
int a = 10;
}
//第三个执行
static int a = 20;
//第二个执行
public A(){
System.out.println("无参构造");
int a = 30;
}
}
public class Test05 {
static {
System.out.println("Main所在的类加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//1、主动引用
//Son son = new Son();//由于父类没有初始化,所以在调用子类的时候会先初始化父类
//2、反射也会产生主动引用
//Class.forName("com.yjj.reflection.Son");//先主动引用然后在反射,所以浪费了资源
//以下不会发生类的初始化
//3、子类调用父类静态的东西,子类不会被加载
//System.out.println(Son.b);//只是调用了Father的b,相当于Father.b
//4、通过数组也不会加载,只加载main类
// Son[] sons = new Son[5];
// Father[] fathers = new Father[10];
//5、调用常量也不会加载常量所在的类
System.out.println(Son.M);//常量在链接阶段就存入调用类的常量池中了
}
}
class Father {
static int b = 2;
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
}
static final int M = 1;//常量
}
类加载器的作用
- 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
- 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,他将维持加载(缓存)一段时间。JVM垃圾回收机制可以回收这些Class对象
- Java核心类库–rt.jar包
public class Test06 {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类加载器--->用户加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);//AppClassLoader
//获取系统类加载器的父类加载器--->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);//ExtClassLoader
//获取扩展类加载器的父类加载器--->根加载器(C/C++编写),Java无法直接访问
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//null
//测试当前类是那个加载器加载的
ClassLoader classLoader = Class.forName("com.yjj.reflection.Test06").getClassLoader();
System.out.println(classLoader);
//测试JDK内置的类Object类是谁加载的
ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader1);//根加载器,null
//获得系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
/*
C:\Program Files\Java\jdk1.8.0_271\jre\lib\charsets.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\deploy.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\access-bridge-64.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\cldrdata.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\dnsns.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\jaccess.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\jfxrt.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\localedata.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\nashorn.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunec.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunjce_provider.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunmscapi.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunpkcs11.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\zipfs.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\javaws.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\jce.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\jfr.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\jfxswt.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\jsse.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\management-agent.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\plugin.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\resources.jar;
C:\Program Files\Java\jdk1.8.0_271\jre\lib\rt.jar; //所有写的东西都在这里
D:\IDEA\Java\out\production\基础语法;
D:\IDEA\Java\lib\kotlin-stdlib.jar;
D:\IDEA\Java\lib\kotlin-reflect.jar;
D:\IDEA\Java\lib\kotlin-test.jar;
D:\IDEA\Java\lib\kotlin-stdlib-jdk7.jar;
D:\IDEA\Java\lib\kotlin-stdlib-jdk8.jar;
D:\IDEA\Java\基础语法\src\com\yjj\lib\commons-io-2.8.0.jar;
D:\IDEA\IntelliJ IDEA Community Edition 2020.3.1\lib\idea_rt.jar
*/
}
}
- 双亲委派机制:当要进行加载一个类时,系统会在加载器中逐层寻找是否和系统类相同名字的类。防止写了一个和系统类名相同的类,增加了安全性
获取类的信息
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void test(){ }
}
=======================================================================
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test07 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.yjj.reflection.User");
//获得类的属性
Field[] fields = c1.getFields();//只能获取public属性
for (Field field : fields) {
System.out.println(field);//什么都没有
}
fields = c1.getDeclaredFields();//可以获取全部属性
for (Field field : fields) {
System.out.println(field);
}
//获取指定属性
Field name = c1.getDeclaredField("name");
System.out.println(name);
//获得类的方法
//Methods所有方法,Method指定方法
Method[] methods = c1.getMethods();//获得本类和父类的所有public方法
for (Method method : methods) {
System.out.println("public的方法:"+method);
}
methods = c1.getDeclaredMethods();//获得本类的所有方法
for (Method method : methods) {
System.out.println("getDeclaredMethods的方法:"+method);
}
//因为方法涉及重载,需要参数系统才能判断出来你要的是那个方法
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
//获得构造器和前面差不多
//获得指定构造器,比如有参构造
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class);
System.out.println("指定:"+declaredConstructor);
}
}