java内存分析:
类加载的过程:
类的加载与ClassLoader的理解:
类的初始化:
package Collections;
public class text1 {
public static void main(String[]args){
A a=new A();
System.out.println(A.m);
}
}
class A{
static {
System.out.println("A类静态代码块初始化");
m=300;
}
static int m=100;
public A(){
System.out.println("A类的无参构造初始化");
}
}
输出:
A类静态代码块初始化
A类的无参构造初始化
100
为什么最终输出的m值为100呢?
分析如下:
首先类进行加载和链接,如下所示:
注:在链接阶段的准备工作时,编译器会为类变量赋默认值为0,即此时的m为0
链接完毕后进行类的初始化,这一过程将会执行类构造器()方法,将类中所有类变量的赋值语句以及静态代码块中的语句收集和合并:
<clinit>() {
System.out.println("A类静态代码块初始化");
m=300;
m=100;
}
第二条m的赋值语句,覆盖了第一条的300,因此最终输出为100
会发生类的初始化的场景:
类的主动引用(一定会发生类的初始化)
类的主动引用:
package Collections;
import static Collections.Son.m;
public class text1 {
static {
System.out.println("Main类被加载");
}
public static void main(String[]args) throws ClassNotFoundException {
Son son=new Son();//会发生类的主动引用
}
}
class Father{
static int a=10;
static{
System.out.println("Father类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m= 300;
}
static int m =100;
static final int M = 1;
}
输出:
Main类被加载
Father类被加载
子类被加载
反射也会产生主动引用:
package Collections;
import static Collections.Son.m;
public class text1 {
static {
System.out.println("Main类被加载");
}
public static void main(String[]args) throws ClassNotFoundException {
Class.forName("Collections.Son");//会发生类的主动引用
}
}
class Father{
static int a=10;
static{
System.out.println("Father类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m= 300;
}
static int m =100;
static final int M = 1;
}
输出:
Main类被加载
Father类被加载
子类被加载
类的被动引用(不会发生类的初始化):
当访问一个静态域时,只有真正声明这个域的类才会被初始化
如:当通过子类引用父类的静态变量,不会导致子类初始化
。
举例:
package Collections;
import static Collections.Son.m;
public class text1 {
static {
System.out.println("Main类被加载");
}
public static void main(String[]args) throws ClassNotFoundException {
System.out.println(Son.a);//通过子类引用父类的静态变量
}
}
class Father{
static int a=10;
static{
System.out.println("Father类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m= 300;
}
static int m =100;
static final int M = 1;
}
输出:
Main类被加载
Father类被加载
10
通过数组定义类引用,不会触发此类的初始化:
举例:
package Collections;
import static Collections.Son.m;
public class text1 {
static {
System.out.println("Main类被加载");
}
public static void main(String[]args) throws ClassNotFoundException {
Son[] arry=new Son[5];//定义一个Son类型的数组
}
}
class Father{
static int a=10;
static{
System.out.println("Father类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m= 300;
}
static int m =100;
static final int M = 1;
}
输出:
Main类被加载
引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
举例:
package Collections;
import static Collections.Son.m;
public class text1 {
static {
System.out.println("Main类被加载");
}
public static void main(String[]args) throws ClassNotFoundException {
System.out.println(Son.M);//M的属性为final表示它为一个常量
}
}
class Father{
static int a=10;
static{
System.out.println("Father类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m= 300;
}
static int m =100;
static final int M = 1;
}
输出:
Main类被加载
1