一个类被初始化的过程?
加载: classpath、jar包、网络、某个磁盘位置下的类的class二进制字节流读进来,在内存中生成一个代表这个类的java.lang.Class对象放入元空间,此阶段我们程序员可以干预,我们可以自定义类加载器来实现类的加载;
验证: 验证Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证虚拟机的安全;
准备: 类变量赋默认初始值,int为0,long为0L,boolean为false,引用类型为null;常量赋正式值;
解析: 把符号引用翻译为直接引用;
**初始化:**我们new一个类的对象,访问一个类的静态属性,修改一个类的静态属性,调用一个类的静态方法,用反射API对一个类进行调用,初始化当前类,其父类也会被初始化… 那么这些都会触发类的初始化;(赋真正的值)
使用: 使用这个类;
卸载:
1.该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例;
2.加载该类的ClassLoader已经被GC;
3.该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法;
静态变量==准备
public static final Stringstr="测试"
静态变量==准备阶段赋值为null,初始化阶段赋值为 静态变量
public static Stringstr="测试1"
变量==创建对象的时候赋值(new 对象的时候)
public String filed="水电费"
静态代码块===初始化阶段的时候执行
static{
}
非静态代码块==创建对象的时候执行(new 对象的时候)
{
}
构造器==创建对象的时候执行(new 对象的时候)
继承时父子类的初始化顺序是怎样的?
父类–静态变量
父类–静态初始化块
子类–静态变量
子类–静态初始化块
父类–变量
父类–初始化块
父类–构造器
子类–变量
子类–初始化块
子类–构造器
JVM中不同的类加载器加载哪些文件?
1、启动类加载器(Bootstrap ClassLoader):(根的类加载器)C++语言实现的
<JAVA_HOME>\jre\lib\rt.jar,resources.jar、charsets.jar
被-Xbootclasspath参数所指定的路径中存放的类库;
2、扩展类加载器(Extension ClassLoader):
sun.misc.Launcher$ExtClassLoader,
<JAVA_HOME>\jre\lib\ext,
被java.ext.dirs系统变量所指定的路径中所有的类库;
3、应用程序类加载器(Application ClassLoader):系统的类加载器
sun.misc.Launcher$AppClassLoader
加载用户类路径(ClassPath)上所有的类库;
JVM类加载的双亲委派模型
双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当上一层类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到这个类)时,下一层类加载器才会尝试自己去加载;
JDK为什么要设计双亲委派模型,有什么好处?
- 确保安全,避免Java核心类库被修改;
- 避免重复加载
- 保证类的唯一性
可以打破JVM双亲委派模型吗?如何打破JVM双亲委派模型?
可以
想要打破这种模型,那么就自定义一个类加载器,重写其中的loadClass方法,使其不进行双亲委派即可;
如何自定义自己的类加载器?
1、继承ClassLoader
2、覆盖findClass(String name)方法 或者 loadClass() 方法;
findClass(String name)方法 不会打破双亲委派;
loadClass() 方法 可以打破双亲委派;
ClassLoader中的loadClass()、findClass()、defineClass()区别?
loadClass() 就是主要进行类加载的方法,默认的双亲委派机制就实现在这个方法中;
findClass() 根据名称或位置加载.class字节码;
definclass() 把字节码转化为java.lang.Class;
1、当我们想要自定义一个类加载器的时候,并且想破坏双亲委派模型时,我们会重写loadClass()方法;
2、如果我们想定义一个类加载器,但是不想破坏双亲委派模型的时候呢?可以可以重写findClass方法(),findClass()方法是JDK1.2之后的ClassLoader新添加的一个方法,这个方法只抛出了一个异常,没有默认实现;
JDK1.2之后已不再提倡用户直接覆盖loadClass()方法,而是建议把自己的类加载逻辑实现到findClass()方法中;
所以,如果你想定义一个自己的类加载器,并且要遵守双亲委派模型,那么可以继承ClassLoader,并且在findClass()中实现你自己的加载逻辑即可;
Class.forName和Classloader.loaderClass的区别
Class.forName得到的class是以及初始化完成的
Classloader.loaderClass得到的class还没有初始化的