类加载及对象创建

    首先说说可以引起类初始化的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对象并进行初始化过程,即调用类构造函数。详

情请看

    类加载及对象创建_第1张图片

    类名.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());
    }
}


你可能感兴趣的:(java语言)