前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多说两句关于ClassLoader的面试题

多说两句关于ClassLoader的面试题

作者头像
PhoenixZheng
发布2018-09-29 11:38:15
1.6K0
发布2018-09-29 11:38:15
举报
文章被收录于专栏:Phoenix的Android之旅

Java的高级知识中ClassLoader是很重要的一环。面试中有很多关于ClassLoader的问题,今天分析一道例子。

问题

场景:假设有三个类 A B C,B和C跟A类不在一个路径下。A使用B类,但没办法通过直接引用的方法使用它。B类对C有引用。 问题1:A如何访问B类? 问题2:B和C类的ClassLoader是谁?

我们分两篇说明这两个问题。今天先分析问题1。

为什么A不能直接引用B类

类的加载是通过ClassLoader去做的,当A类要使用B类的时候,A的ClassLoader首先会从最根的ClassLoader去寻找类B,然后依次往下找,最终如果A的ClassLoader也找不到的话,会报ClassNotFoundException。这就是双亲委派的简单原理。

A类的ClassLoader找不到B类的原因是,A的ClassLoader只会去找同个路径下的class文件,而B不在这个路径下。

接下来回答怎么加载B类的问题

自定义ClassLoader

类的加载是通过ClassLoader去加载class文件。对于ClassLoader,其实我们可以随心所欲的自定义它,只要重载findClass()方法就可以。

这里实现了一个可以根据路径加载class的ClassLoader,

代码语言:javascript
复制
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * Created by phoenix on 2018/3/12.
 */

public class DiskClassLoader extends ClassLoader {

    private String mFilePath;

    public DiskClassLoader(String mFilePath) {
        this.mFilePath = mFilePath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String fileName = getFileName(name);
        File file = new File(mFilePath, fileName);
        try {
            FileInputStream ins = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len = 0;
            try {
                while((len = ins.read()) != -1) {
                    bos.write(len);
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
            byte[] data = bos.toByteArray();
            ins.close();
            bos.close();
            return defineClass(name, data, 0, data.length);
        } catch (IOException exp) {
            exp.printStackTrace();
        }
        return super.findClass(name);
    }

    private String getFileName(String name){
        int index = name.lastIndexOf('.');
        if(index == -1) {
            return name + ".class";
        } else {
            return name.substring(index) + ".class";
        }
    }
}

它的构造方法接受一个String作为路径,重载的findClass方法可以加载指定的class文件。 其实逻辑很简单,不过二十多行代码,这里就不解释了。 下面看如何使用它。

A的代码像下面这样,

代码语言:javascript
复制
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class A {

  private static void println(Object msg) {
    System.out.println("A " + msg);
  }

  public static void main(String[] args) {
    // System.out.println("Ming looking for socker");
    println(A.class.getClassLoader());
    checkClassCast();
  }

  private static void checkClassCast() {
    try {
      DiskClassLoader loader1 = new DiskClassLoader("../BDirectory");

      Class class1 = loader1.findClass("B");

      Object classB = class1.newInstance();

      Method method = class1.getDeclaredMethod("loaderTest", (Class<?>[]) null);//<--B类的方法
      method.invoke(classB, (Object[])null);
    } catch(Exception e){
      e.printStackTrace();
    }
  }
}

代码注释中 loaderTest()是B类里的方法,通过自定义ClassLoader,我们也能调用上在另外路径下的类B了。

下次我们会再聊聊如何回答第二个问题, B和C的ClassLoader是谁?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 为什么A不能直接引用B类
  • 自定义ClassLoader
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档