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文件时就已经加载到内存的常量池了。
浙公网安备 33010602011771号