首先说说可以引起类初始化的4种方法(jdk1.7中还有一种就不提了)
1. new ,invokestatic, getstatic,putstatic
2. 反射
3. 主类包含main方法的类
4. 父类先初始化,子类后初始化
new方法会使用new关键字因此会引起类初始化,在初始化过程会调用类构造方法,初始化完成之后接着调用实例构造方法,因此
new方法会将这两者都进行调用从而生成实例对象,一般静态方法的调用只会引起初始化类构造方法的调用。在new方法执行过程中
会进行类的加载过程,生成Class对象(是由类加载器的方法loadClass->defineClass)。
Class.forName(className)方法等效于Class.forName(className, true, currentLoader),这个方法会直接调用当前类的类加载器
进行类加载(可以自己制定类加载器进行加载loadClass->defineClass)生成了类Class对象并进行初始化过程,即调用类构造函数。详
情请看
类名.class 这种方法虽然可以获取Class对象但是并没有进行类的初始化过程。
实例.getClass方法,既然都有实例,之前肯定已经进行了初始化过程,即调用了类构造器和实例构造器,只不过返回已经生成的
Class对象。
类加载器.loadClass方法加载类,并没有进行初始化,只是生成Class对象并没有进行初始化过程。
package dahua;
public class Sample
{
static
{
System.out.println("s");
}
}
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"; // class文件的扩展名
public MyClassLoader(String name) {
super(); // 让系统类加载器成为该类加载器的父加载器
this.name = name;
}
public MyClassLoader(ClassLoader parent, String name) {
super(parent); // 显式指定该类加载器的父加载器
this.name = name;
}
@Override
public String toString() {
return this.name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
/**
* @param 类文件的名字
* @return 类文件中类的class对象
*
* 在这里我们并不需要去显示的调用这里的findclass方法,在上篇文章中,我们通过查看
* loadclass的源码可以发现,她是在loadclass中被调用的,所以这里我们只需重写这个方法,
* 让它根据我们的想法去查找类文件就ok,他会自动被调用
*
*
* defineClass()将一个 byte 数组转换为 Class 类的实例。必须分析 Class,然后才能使用它
* 参数:
* name - 所需要的类的二进制名称,如果不知道此名称,则该参数为 null
* b - 组成类数据的字节。off 与 off+len-1 之间的字节应该具有《Java Virtual Machine Specification 》定义的有效类文件的格式。
* off - 类数据的 b 中的起始偏移量
* len - 类数据的长度
*/
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = this.loadClassData(name);//获得类文件的字节数组
return this.defineClass(name, data, 0, data.length);//
}
/**
*
* @param 类文件的名字
* @return 类文件的 字节数组
* 通过类文件的名字获得类文件的字节数组,其实主要就是用
* 输入输出流实现。
*/
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 ex) {
ex.printStackTrace();
} finally {
try {
is.close();
baos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return data;
}
public static void main(String[] args) throws Exception {
//创建一个loader1类加载器,设置他的加载路径为d:\\serverlib\\,设置默认父加载器为系统类加载器
MyClassLoader loader1 = new MyClassLoader("loader1");
Class str = loader1.loadClass("dahua.Sample");
System.out.println("finish "+str.toString());
}
}