JVM结构图(简略)
new对象jvm中的实现(简略)
Pojo pojo = new Pojo();
类加载器加载Pojo.class(类),得到Class(类对象 [类模板,只加载一次,每次实例化对象都通过它实现] ),再通过Pojo类对象实例化pojo对象,实例化后的pojo
在栈,new Pojo()
在堆,new出来的都在堆,堆中的数据都有一个十六进制的地址值,栈中的pojo
对应new Pojo()
的地址值
类加载器
- 虚拟机自带的加载器
- 启动类(根)加载器
- 扩展类加载器
- 应用程序(系统)类加载器
获取类加载器
public static void main(String[] args) {
Pojo pojo = new Pojo();
//获取pojo对象的Pojo类对象
Class<? extends Pojo> aClass = pojo.getClass();
//获取类对象的类加载器 应用程序类加载器
ClassLoader classLoader = aClass.getClassLoader();
System.out.println(classLoader);
//获取应用程序类加载器的父类加载器 扩展类加载器
System.out.println(classLoader.getParent());
//获取扩展类加载器的父类加载器 启动类加载器 java无法直接获取
System.out.println(classLoader.getParent().getParent());
}
输出结果
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1b6d3586
null
通过实例化的pojo对象的getClass()
方法获取Pojo类对象,再通过类模板的getClassLoader()
方法获取类加载器,此时返回的是应用程序类加载器(AppClassLoader),通过getParent()
方法获取应用程序类加载器的父类加载器:扩展类加载器(ExtClassLoader),再通过getParent()
方法获取扩展类加载器的父类加载器:启动类加载器(BootstrapClassLoader),通过代码看到返回的结果为null
,因为启动类加载器是加载本地C++编写的文件,java不能直接获取,所以返回null
双亲委派机制
自定义一个类,java.lang.String
,方法toString()
package java.lang;
public class String {
@Override
public String toString() {
return "hello java";
}
public static void main(String[] args) {
String s = new String();
s.toString();
}
}
输出结果
错误: 在类 java.lang.String 中找不到 main 方法
明明有main方法,怎么回事呢,这是因为Java的双亲委派机制
双亲委派机制
即加载一个类时,类加载器不先自己加载,而是先上委派父类进行加载,如果父类上还存在父类就继续向上委派,直到最顶层类加载器,如果最顶层类加载器找到了这个类就进行加载,如果没找到就一层一层委派给子类,子类找到这个类了就进行加载,如果到了最底层子类还是找不到这个类,就抛出异常ClassNotFoundException
因为我们自定义的类java.lang.String
和JDK提供的类冲突了,在委派给启动类加载器时找到了JDK提供的String类,但是JDK提供的String类里面没有main()
这个方法,所以报错找不到main()
方法