Java基础之类的加载过程

为什么说Java语言的一大特点是平台无关性?

    因为java程序是直接与jvm进行交互的,而通过jvm与操作系统进行交互,不同的操作系统会有不同的jvm,所以java程序可以在不同的操作系统中执行。

java代码在执行过程中会经历如下阶段:

    加载——验证——准备——解析——初始化——使用——卸载,  其中加载,验证,准备,初始化都属于类加载机制中的加载过程。

加载:

    java中的加载时包括静态加载动态加载的。

   静态加载:使用new()得到对象的就是静态编译,当类发生了内部结构的变化时,需要重新编译之后才能生效。而动态加载则不同:

    动态加载是一种程序运行机制,程序在运行时就加载到库或内存,然后检索库中的变量或函数的地址,并运行变量和函数。

类的加载通过类加载器或者反射的方式来进行:

1          Class class = ClassLoader.getSystemClassLoader().loadClass(name);    //通过类加载器加载一个类,返回的是这个类的一个引用。
2          Object obj = class.newInstance();    //通过反射来得到类对象

通过反射方式,我们可以在程序运行时加载未加载进来的类(Spring的控制反转)

1 Classtype=Class.forName(name);        //加载
2 Object obj=type.newInstance();          //实例化        

那么,通过类加载器加载与反射class.forName()加载的区别在哪呢?

    我新建两个简单的类Line和Point来测试其中静态代码块在类加载器中和反射加载情况下的加载顺序。

 1 package model.strategy;
 2 
 3 /**
 4  * @author kevinfan
 5  * @date 2020/02/15
  * 测试类加载过程静态代码的加载顺序
6 **/ 7 public class Line { 8 //声明静态代码块 9 static { 10 System.out.println("我是静态代码块中的Line"); 11 } 12 //声明常量 13 static final String NBA = "Nation Basktball Association"; 14 //声明静态变量 15 static String sv = "我是静态变量"; 16 //声明静态方法 17 public static void testStaticVar(){ 18 System.out.println("我是静态方法,我含有的常量为NBA"+NBA+",静态变量为sv"+sv); 19 } 20 }
 1 package model.strategy;
 2 
 3 /**
 4  * @author kevinfan
 5  * @date 2020/02/15
 6  **/
 7 public class Point {
 8     static {
 9         System.out.println("我是静态代码块中的point");
10     }
11 }
 1 package model.strategy;
 2 
 3 import static model.strategy.Line.NBA;
 4 
 5 /**
 6  * @author kevinfan
 7  * @date 2020/02/15
 8  **/
 9 public class LoadTest {
10     public static void main (String[] args){
11         //将Line和Point完整类名加载进来
12         String lineName = "model.strategy.Line";
13         String pointName = "model.strategy.Point";
14         try {
15             testLoad(lineName,pointName);
16         } catch (ClassNotFoundException e) {
17             e.printStackTrace();
18         }
19     }
20     public static void testLoad(String lineName,String pointName) throws ClassNotFoundException {
21 
22         //测试加载器
23         Class classref = ClassLoader.getSystemClassLoader().loadClass(lineName);
24         Class pointef = ClassLoader.getSystemClassLoader().loadClass(pointName);
25         System.out.println("Line经过classLoader形式的加载:"+classref.getName()+",常量为NBA:"+NBA+",静态变量sv:");
26         //Line.testStaticVar();
27         System.out.println("Point经过classLoader形式的加载:"+pointef.getName());
28 
29         try {31             Point point = (Point)pointef.newInstance();
32         } catch (InstantiationException e) {
33             e.printStackTrace();
34         } catch (IllegalAccessException e) {
35             e.printStackTrace();
36         }
37         //测试 Class.forName形式的加载
38         System.out.println("============class.forNmae分割线=============");
39         Class lineref = Class.forName(lineName);
40         Class pointref = Class.forName(pointName);
41         System.out.println("Line经过class.forname()形式的加载:"+lineref.getName());
42         System.out.println("Point经过class.forname()形式的加载:"+pointref.getName());
43     }
44 }

结果如下:

1 Line经过classLoader形式的加载:model.strategy.Line,常量为NBA:Nation Basktball Association,静态变量sv:
2 Point经过classLoader形式的加载:model.strategy.Point3 我是静态代码块中的point
4 ============class.forNmae分割线=============
5 Line经过class.forname()形式的加载:model.strategy.Line
6 Point经过class.forname()形式的加载:model.strategy.Point

从以上运行结果可以看出:

class.forName()方式加载会将编译好的class问价加载到jvm中,并且还会对类进行解释,执行其中的static代码块。而类加载器的方式只是将class文件加载到jvm中,在newInstance()实例化时才会执行static静态代码块。

此外,可以注意代码中出现的常量NBA,常量是源码编译成class文件时就已经加载到内存的常量池了。

posted @ 2020-02-15 17:01  奔玻尔霸  阅读(107)  评论(0)    收藏  举报