java中类的加载_Java中类什么时候加载详解

本文探讨了Java中的类加载机制,通过一个示例展示了类B和类C在何时加载公共类A。当D类仅实例化B类但不调用其方法时,A类不会被加载。然而,当D类实例化C类时,由于C类在声明成员变量时即创建了A类的对象,因此A类会被加载。总结了Java的按需加载原则,即只有在使用类时才会加载该类。
摘要由CSDN通过智能技术生成

假设,有一个公共类A。另外两个B、C类的内部都使用了A类,并且都new出了对象。现在有另外一个D类,其内部new出了B、C两类的实例。试分析他们分别在什么时候被JVM加载?

图形表示如下:

127075687_1_20180313015235238.png

(纠正一下,图中的“内存的数据产生”改为:类什么时候被加载,什么时候被实例化。) 第1步:公共类A:public class ClassA {

/**

* 定义Class A

*/

//静态初始化块

static {

System.out.println("ClassA----我被加载了");

}

private static int age=20;

private String name="xiaowang";

public static int getAge() {

return age;

}

public String getName() {

return name;

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

第2步:B类(内部使用了A类)public class ClassB {

/**

* 定义Class B

*/

static {

System.out.println("ClassB----我被加载了");

}

private ClassA classA;

public void myName() {

System.out.println("B方法---开始");

classA= new ClassA();

System.out.println("B方法---打印A的成员变量值:"+classA.getName());

System.out.println("B方法---结束");

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

第3步:C类(内部也使用了A类)public class ClassC {

/**

* 定义Class B

*/

static {

System.out.println("ClassC----我被加载了");

}

private ClassA classA= new ClassA();

public void myName() {

System.out.println("C方法---开始");

System.out.println("C方法---打印A的成员变量值:"+classA.getName());

System.out.println("C方法---结束");

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18到这里,问一下大家:B、C两个类有什么不一样的地方?BinGo,成员变量classA实例化的地方不一样,B是在方法中new出对象,C是定义成员变量引用的时候就new对象了。(咋一看,感觉没什么不一样,都是实例化,但是这里面蕴含了JVM的一个思想,那就是–JVM运行程序时,是用到该类的对象,才会去加载该类到方法区。如果方法区已经加载过该类了,不会再去加载该类。)

注意一下:A、B、C 三个类都有一个静态初始化块,当一个类被加载的时候,块内的代码会得到执行。方便我们知道那个类被加载了。

第4步:D类(D类使用了B、C两个类)public class DTest {

/**

* 定义Class D

*/

static {

System.out.println("ClassD----我被加载了");

}

//程序入口:

public static void main(String[] args) {

// TODO Auto-generated method stub

ClassB classB = new ClassB();

ClassC classC = new ClassC();

classB.myName();

classC.myName();

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

好了,我们先来运行一下程序,打印一下结果:看看是怎么样的。ClassD----我被加载了

ClassB----我被加载了

ClassC----我被加载了

ClassA----我被加载了

B方法---开始

B方法---打印A的成员变量值:xiaowang

B方法---结束

C方法---开始

C方法---打印A的成员变量值:xiaowang

C方法---结束

看不懂?没关系,下面我们一步步把D的程序来肢解。

1、如下代码,我们在程序入口里面,只实例化B类,并不执行B类实例的myName()方法。那么请问,ClassA会被加载吗?public class DTest {

/**

* 定义Class D

*/

static {

System.out.println("ClassD----我被加载了");

}

//程序入口:

public static void main(String[] args) {

ClassB classB = new ClassB();

//注意:我们注释掉了,下面这个语句。

//classB.myName();

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15答案是:ClassA不会被加载。运行一下看看结果:ClassD----我被加载了

ClassB----我被加载了

2、同样的情况,我们在程序入口里面,只实例化C类,那么请问,ClassA会不会被加载呢?public class DTest {

/**

* 定义Class D

*/

static {

System.out.println("ClassD----我被加载了");

}

//程序入口:

public static void main(String[] args) {

ClassC classC = new ClassC();

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

我们运行一下看看结果:ClassD----我被加载了

ClassC----我被加载了

ClassA----我被加载了

咦,为什么这次ClassA 会被加载了呢?对比一下,发现B、C两个类,在声明成员变量 classA的时候,B类中只是声明了一个引用变量–classA,并没给它赋值。只在方法被使用的时候,才new对象,而C类是声明后,直接new出对象赋值。所以A类会被加载。这也正好符合了java的特点,使用时,再加载。强烈提示:java中的引用变量,其实就是一个地址指针,只是Java语言中没有指针这一说法罢了。以后一定要认为变量就是——地址指针。

3、那么如果D类只使用了B类,什么情况下,A类会被JVM 加载到方法区呢?我们来做下面这个实验。public class DTest {

/**

* 定义Class D

*/

static {

System.out.println("ClassD----我被加载了");

}

//程序入口:

public static void main(String[] args) {

ClassB classB = new ClassB();

classB.myName();

}

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

运行一下,结果如下:ClassD—-我被加载了 ClassB—-我被加载了 B方法—开始 ClassA—-我被加载了 B方法—打印A的成员变量值:xiaowang B方法—结束

从结果中,可以看出,ClassA的加载,是在B的实例方法,被调用的时候,才去加载。 总结一下,本文的中心思想是讲了,一个类什么时候会被JVM加载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值