类加载器 ClassLoader
1.什么是类加载器?有什么作用?
2.类加载器的分类(根、扩展、应用、自定义)
3.加载方式(显式、隐式)
4.自定义类加载器
5.网络类加载器
==================================================
说白了:根据条件得到.class文件,后面我们利用反射技术取.class中的属性和方法
委托、可见性、单一性、安全
d:\\Abc.class
==================================================
1.什么是类加载器
问题一:实例化对象的方式:
a、直接new:通过模板进行实例化
b、通过类加载器来实现
问题二:类的来源
a、我们自己写的类
b、导入的jar包中的类
c、JDK中自带的类库
所谓类加载器就是用来加载Java类到Java虚拟机中,又称为“类类”。
说明了:就是负责将.class字节码文件送到JVM中运行的类。
Java虚拟机使用Java类的方式:
Java源程序(.java文件)在经过Java编译器编译之后被转换在Java字节码(.class文件),类加载器就负责读取Java字节码,并转换成java.lang.Class类的一个实例。
每个这样的实例用来表示一个Java类,通过此实例的newInstance()方法可以创建出该类的一个对象。实际情况可能更复杂。
说白了:我们写的源文件.java先通过编译器(javac)编释成类文件,然后送到JVM虚拟机去执行,谁送它去JVM虚拟机?就是类加载器。
注意:
a. 类加载器本身就是一个类。
b. 类加载器责责加载文件系统、网络或其他来源的类文件。
c. 基本上所有的类加载器都是java.lang.ClassLoader类的一个实例。
-------------------------------------
java.lang.ClassLoader类:
方法:
getParent()
//返回该类加载器的父类加载器
loadClass(String n)
//加载名称为n的类,返回的结果是java.lang.Class类的实例
findClass(String n)
//查找名称为n的类,返回的结果是java.lang.Class类的实例
findLoaderClass(String n)
//查找名称为n的已被加载过的类,返回的结果是java.lang.Class类的实例
defineClass(String n, byte[] b, start, end)
// 把字节数组b中的内容转换成Java类,返回实例,该方法被声明为final
resolveClass(Class> c)
//链接指定的Java类
-------------------------------------------------
Class.forName(xxx.xx.xx); //要求JVM查找并加载指定的类
如何查看谁加载的对象(类加载器)
System.out.println(对象名.getClass().getClassLoader());
如何查看类加载器的父类
System.out.println(对象名.getClass().getClassLoader().getParent());
user.getClass().getClassLoader();//根据对象名得到它的类加载器
String.class.getClassLoader(); //根据类名得到它的类加载器
user.getClass().getClassLoader().getParent();
================================================
2.类加载器的分类
根类加载器
扩展类加载器
应用类加载器
自定义类加载器
2.1 根类加载器(null):也称引导加载器
该加载器没有父加载器,它是所有类加载器的父加载器。
负责加载虚拟机的核心类库(JRE/lib/rt.jar中的JDK类文件)。
返回null的基本上就是根加载器,也有可能是其它的。
2.2 扩展类加载器(Ext):
其父加载器为根类加载器。
负责从java.ext.dirs系统属性所指定的目录中加载类,
或者从JDK安装目录的jre/lib/ext子目录下加载类库。
将加载类的请求先委托给它的父加载器,也就是Bootstrap,如果没有成功加载,再从jre/lib/ext或者java.ext.dirs系统属性定义的目录下加载类。
System.out.println(User.getClass().getClassLoader().getParent());
//返回:……ExtClassLoader……
2.3 应用类加载器(App):
也称为系统类加载器,它的父加载器为扩展类加载器。
负责加载我们自己写的类,它是用户自定义类的默认父加载器。
System.out.println(User.getClass().getClassLoader());
//返回:……AppClassLoader……
2.4 自定义类加载器
类加载器之间的关系:
根类加载器 ——> 扩展类加载器 ——> 应用类加载器 ——> 自定义类加载器
(爷爷) (父亲) (儿子) (儿子的儿子)
=================================================
3.加载方式分类
3.1 显式加载(字符串模式)
Class c = Class.forName("com.temp.Person");
Person p = (Person)c.newInstance();
3.2 隐式加载
Person p = new Person();
==================================================
4.自定义类加载器
自己写个类加载器,加载指定路径中的类。
比如有个类的.class文件不在项目中,如何加载?例如加载d:\\com\\entity\\User.class
操作步骤:
(1)创建类,继承类加载器ClassLoader,要拥有类加载器的所有功能。
(2)重写查找类的方法findClass()。
参数:String name 表示要加载的类的路径
Class>:找到文件后,再返回该类的.class文件
(有技术点:将文件转化成Class文件)
//代码:
public class MyClassLoader extends ClassLoader {
//重写查找类的方法
/**
* String name 要加载的文件的的路径
* Class> 找到文件后 再返回(将文件流 转换为一个class)
*/
protected Class> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
//1.找到.class文件的路径(假设e:\cs\com\entity\User.cs文件)
// 将类的路径字符串中的“.”过滤成“/”
String str=name.replaceAll("\\.", "/");
// 指定要加载的文件路径
str="e:\\cs\\"+str+".cs";
//2.声明一个Class,用于接收类转换的class文件
Class c=null;
try {
//将文件流转换成class文件
FileInputStream fis=new FileInputStream(str);
//声明一个数组 其大小要刚好与文件大小相同
byte[] bs=new byte[fis.available()]; //fis.available()文件长度
//将文件内容读取到bs中
fis.read(bs);
//重点:将字节流转换为其对应的Class
c=this.defineClass(null, bs, 0, bs.length);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return c;
}
}
(3)利用自定义加载器去加载非项目里面的字节码
//先声明并实例化一个自定义类加载器
MyClassLoader mcl = new MyClassLoader();
//指定类加载器(mcl)
Class c = Class.forName("com.entity.Person", true, mcl);
System.out.println(c.getClassLoader());
========================================
5.网络类加载器:
案例:将User.class放到Tomcat/webapp/temp/中。
//声明一个网址对象
URL url = new URL("http://localhost:8080/temp/");
//声明一个网络类加载器,这里可以加载一组,但这我们只放了一个
URLClassLoader ucl = new URLClassLoader(new URL[]{url});
//利用网络类加载器去加载指定的类
Class c = Class.forName("com.entity.Person", true, ucl);
System.out.println(c.getClassLoader());