黑马程序员-类加载器

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

 

java.lang.ClassLoader 类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class 类的一个实例。

 

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:

引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader

扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader() 来获取它

 

Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。下面自己编写了个累加器FileSystemClassLoader来实现:代码如下:

 

package test.java;

public class LoaderClass {
 @SuppressWarnings("unused")
 private LoaderClass loader;

 public void newInstance(Object loader) {
  this.loader = (LoaderClass) loader;
 }
}

 

package test.java;

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

public class FileSystemClassLoader extends ClassLoader {
 private String rootDir;

 public FileSystemClassLoader(String rootDir) {
  this.rootDir = rootDir;
 }

 @SuppressWarnings({ "rawtypes", "unchecked" })
 public Class findClass(String name) {
  byte[] b = loadClassData(name);
  if (b == null) {
   try {
    throw new ClassNotFoundException();
   } catch (ClassNotFoundException e) {
    e.printStackTrace();
   }
  } else {
   return defineClass(name, b, 0, b.length);
  }
  return null;
 }

 private byte[] loadClassData(String className) {
  File classFile = new File(this.addClassNameToPath(className));
  try {
   InputStream in = new FileInputStream(classFile);
   ByteArrayOutputStream out = new ByteArrayOutputStream();
   int bufferSize = 4096;
   byte[] b = new byte[bufferSize];
   int length = 0;
   while ((length = in.read(b)) != -1) {
    out.write(b, 0, length);
   }
   return out.toByteArray();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return null;
 }

 protected String addClassNameToPath(String className) {
  return this.rootDir + File.separatorChar
    + className.replace('.', File.separatorChar) + ".class";
 }
}

 

package test.java;

import java.lang.reflect.Method;

public class LoaderClassTest {

 public static void main(String[] args) throws Exception {
  String classPath = "D:\\workspace\\Test\\bin";
  FileSystemClassLoader fscl1 = new FileSystemClassLoader(classPath);
  FileSystemClassLoader fscl2 = new FileSystemClassLoader(classPath);
  String className = "test.java.LoaderClass";
  Class<?> c1 = fscl1.findClass(className);
  Object o1 = c1.newInstance();
  Class<?> c2 = fscl2.findClass(className);
  Object o2 = c2.newInstance();
  Method newInstanceMethod = c1.getMethod("newInstance",
    java.lang.Object.class);
  newInstanceMethod.invoke(o1, o2);
 }
}

运行结果:

Exception in thread "main" java.lang.reflect.InvocationTargetException
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at test.java.LoaderClassTest.main(LoaderClassTest.java:18)
Caused by: java.lang.ClassCastException: test.java.LoaderClass cannot be cast to test.java.LoaderClass
 at test.java.LoaderClass.newInstance(LoaderClass.java:7)
 ... 5 more
可以看出出现了类转换异常!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值