一、类的加载、连接、初始化
(1)加载:查找并加载类的二进制数据
(2)连接
--验证:确保被加载类的正确性
<1>文件的结构检查:遵从java类文件的固定格式
<2>语义检查:是否符合语法规范
<3>字节码验证:检查每个操作码是否合法,是否可被java虚拟机安全的执行。
<4>二进制兼容的验证:确保相互引用的类之间的协调一致。例如:不能存在引用对象的某个执行方法,抛出NoSuchMethodError错误。
--准备:为类的静态变量分配内存,并将其初始化为默认的值
--解析:把类中的符号引用转换为直接引用
(3)初始化:为类的静态变量赋予正确的初始值

package classLoader;
class SingleTon {
private static SingleTon singleTon = new SingleTon();
public static int counter1;
/* class文件加载的步骤:(1)加载;(2)连接(验证、准备、解析);(3)初始化 */
/* counter2在连接->准备阶段被赋予默认初始值0,在初始化阶段被赋予=等号右边的0值*/
public static int counter2 = 0;
// private static SingleTon singleTon = new SingleTon();
private SingleTon() {
counter1++;
counter2++;
}
public static SingleTon getInstance() {
return singleTon;
}
}
public class Test1 {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
/*
* 类的加载:将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区中,然后在堆区中创建一个java.lang.Class对象
* ,用来封装类在方法区内的数据结构
*/
singleTon.getClass();
singleTon.getClass().getClassLoader();
System.out.println("counter1 = " + SingleTon.counter1);
System.out.println("counter2 = " + SingleTon.counter2);
}
}执行结果:打印:
counter1 = 1
counter2 = 0
counter2在连接->准备阶段被赋予默认初始值0,在初始化阶段被赋予=等号右边的0值
二、主动使用、被动使用
java程序对类的使用分为主动使用和被动使用。
每个类或接口被java程序“首次主动使用”是才会被java虚拟机初始化。
主动使用(六种)
(1)创建类的实例
(2)访问某个类或接口的静态变量,或对静态变量赋值。
(3)调用类的静态方法
(4)反射;Class.forName
(5)初始化一个类的子类
(6)java虚拟机启动时被标明为启动的类
除了以上六种情况,都叫被动使用,都不会导致类的初始化。
三、类的加载
指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区中内,然后在堆区创建一个java.lang.Class的对象,用来封装类在方法区内的数据结构。

四、类加载器
两种类加载器:
(1)java虚拟机自带的加载器
<1>根加载器:没有父加载器;负责加载核心类库,如java.lang等。从系统属性sun.boot.class.path所指定的目录中加载类库。依赖于底层操作系统,不继承与ClassLoader
<2>扩展类加载器:其父加载器为根加载器。从java.ext.dirs系统属性中所指路径加载类库(jre/lib/ext)。java.lang.ClassLoader的子类
<3>系统类加载器:也称应用类加载器,父加载器为扩展类加载器。从环境变量classpath目录中加载
System.out.println(System.getProperty("sun.boot.class.path"));
System.out.println(System.getProperty("java.ext.dirs"));
(2)用户自定义的类加载器
java.lang.ClassLoader的子类


父委托机制的优点是:提高系统的安全性。因为在该机制下:用户自定义的类加载器不可能加载应该由该父加载器可加载的可靠的类。
每个类加载器都有自己的命名空间,命名空间由该类加载器及所有父加载器所加载的的类组成。在同一个命名空间中,不会出现包名类名完全一样的类;在不同的命名空间中可以出现。
五、自定义类加载器
MyClassLoader.java
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
/** 类加载器的名字 */
private String name;
private String path = "D:\\";
private final String fileType = ".class";
public MyClassLoader(String name) {
/* 让系统类加载器成为该类的父加载器 */
super();
this.name = name;
}
public MyClassLoader(ClassLoader parent, String name) {
/* 显式的指定该类加载器的父加载器 */
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = loadClassData(name);
return this.defineClass(name, data, 0, data.length);
}
private byte[] loadClassData(String name) {
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null;
try {
// this.name = this.name.replace(".", "\\");
is = new FileInputStream(new File(path + name + fileType));
baos = new ByteArrayOutputStream();
int ch = 0;
while (-1 != (ch = is.read())) {
baos.write(ch);
}
data = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
if (baos != null)
baos.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return data;
}
@Override
public String toString() {
return name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public static void main(String[] args) throws Exception {
MyClassLoader loader1 = new MyClassLoader("loader1");
loader1.setPath("H:\\develop\\workspace\\learn_workspace\\classLoader\\class\\serverlib\\");
MyClassLoader loader2 = new MyClassLoader(loader1, "loader2");
loader2.setPath("H:\\develop\\workspace\\learn_workspace\\classLoader\\class\\clientlib\\");
MyClassLoader loader3 = new MyClassLoader("loader3");
loader3.setPath("H:\\develop\\workspace\\learn_workspace\\classLoader\\class\\otherlib\\");
test(loader1);
System.out.println("######");
test(loader2);
System.out.println("######");
test(loader3);
}
public static void test(ClassLoader loader) throws Exception {
Class clazz = loader.loadClass("Sample");
Object obj = clazz.newInstance();
}
}Sample.java
public class Sample {
public int v1 = 1;
public Sample() {
System.out.println("Sample is loader by :"
+ this.getClass().getClassLoader());
new Dog();
}
}Dog.java
public class Dog {
public Dog() {
System.out.println("Dog is loaded by :"
+ this.getClass().getClassLoader());
}
}为了避免eclipse中对环境变量的影响,在cmd中执行。
编译后的文件class文件,测试时放置的路径结构:

cmd中执行结果:

sun.misc.Launcher@AppClassLoader@........代表在”系统/应用类加载器“中加载的。
皮毛笔记整理,待深入
1091



被折叠的 条评论
为什么被折叠?



