JVM 类加载机制

Java的类加载器都有哪些?

每个类加载器都加载哪些类? 

这些类加载之间的父子关系是怎样的? 

什么是双亲委派模型? 

为什么Java的类加载器要使用双亲委派模型?  

如何自定义自己的类加载器,自己的类加载器和Java自带的类加载器关系如何处理?

默认的类加载器只知道如何从本地系统加载类。如果我们的程序只是在本机跑的话,一般来说默认加载器可以应付。 但是如果我们需要加载远程服务器的类,或者说加载网络上的,不是本机上的类的时候,就需要到自定义类加载器。

实现方式:
自定义类加载器可以选择 继承ClassLoader类,重写里面的方法来实现。

1、loadClass(String name,Boolean resolve)方法:不推荐重写,因为loadClass()方法做的工作主要为实现双亲委托模型,我们重写的话可能会破坏该模型,并且也增加自己的开发难度。
2、defineClass(String name,byte[] b,int off,int len)方法,主要用于将原始字节转换为Class对象,也不需要我们重写。
3、findClass(String name)方法,根据名称来查找类。把.class文件的内容放入一个byte[]数组中,供defineClass()方法使用。一般我们就重写这个方法。在这个方法中,我们重新定义从哪里,怎么样读取文件内容。这样我们就可以把从本机上改为从网络上得到类,从而实现自定义类加载器。

步骤:
1、继承ClassLoader类。
2、重写findClass(String name)方法。 在这个方法里面我们重新定义从哪里,怎么读取文件内容到byte[]数组中,供defineClass()使用

package com.study.pattern;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

/**
 * Created by WuTing on 2018/3/6.
 */
public class MyClassLoader extends ClassLoader {
    private static final String FILE_TYPE = ".class";

    private String path;

    public MyClassLoader() {
        super();
    }

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    public Class<?> loadClass(String classFullName) throws ClassNotFoundException {
        return super.loadClass(classFullName);
    }

    @Override
    protected Class<?> loadClass(String classFullName, boolean resolve) throws ClassNotFoundException {
        return super.loadClass(classFullName, resolve);
    }

    @Override
    protected Class<?> findClass(String classFullName) throws ClassNotFoundException {
        byte[] data = this.loadClassData(classFullName);
        return this.defineClass(classFullName, data, 0, data.length);
    }

    private byte[] loadClassData(String classFullName) {
        InputStream is = null;
        byte[] data = null;
        ByteArrayOutputStream outputStream = null;
        try {
            String pathname = getPath() + classFullName.replace(".", "\\") + FILE_TYPE;
            is = new FileInputStream(new File(pathname));
            outputStream = new ByteArrayOutputStream();
            int ch = 0;
            while (-1 != (ch = is.read())) {
                outputStream.write(ch);
            }
            data = outputStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    public static void showClassLoader(ClassLoader loader) throws Exception {
        Class clazz = loader.loadClass("com.study.pattern.Sample"); //Class 全名
        clazz.newInstance();
    }

    public static void main(String[] args) throws Exception {
        MyClassLoader loader1 = new MyClassLoader();
        loader1.setPath("d:\\loader1\\");

        MyClassLoader loader2 = new MyClassLoader(loader1);
        loader2.setPath("d:\\loader2\\");

        MyClassLoader loader3 = new MyClassLoader(null);
        loader3.setPath("d:\\loader3\\");

        showClassLoader(loader1);
        showClassLoader(loader2);
        showClassLoader(loader3);
    }

    public String getPath() {
        if (path == null || path.trim().length() == 0) {
            path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        }
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}
package com.study.pattern;

/**
 * Created by WuTing on 2018/3/6.
 */
public class Sample {
    public Sample() {
        System.out.println("Sample is load by :" + this.getClass().getClassLoader());
    }
}

执行结果:

Sample is load by :sun.misc.Launcher$AppClassLoader@18b4aac2
Sample is load by :sun.misc.Launcher$AppClassLoader@18b4aac2
Sample is load by :com.study.pattern.MyClassLoader@1540e19d

从结果可以看出,当指定了指定了parent,会调用parent的findClass.

  protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) { //存在parent,调用parent的loadClass
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值