类的加载过程
一、类加载机制
类加载全过程
1、加载
2、链接
3、初始化
二、Java程序初始化顺序
/**
* @ClassName Demo01
* @Description 测试程序初始化顺序
* @Author xwd
* @Date 2018/10/23 21:50
*/
public class Demo01 {
public static void main(String[] args) {
B b = new B();
}
}
class A{
static String str1 = "父类A的静态变量";
String str2 = "父类A的非静态变量";
static {
System.out.println("执行了父类A的静态代码块");
}
{
System.out.println("执行了父类A的非静态代码块");
}
public A(){
System.out.println("执行了父类A的构造方法");
}
}
class B extends A{
static String str1 = "子类B的静态变量";
String str2 = "子类B的非静态变量";
static {
System.out.println("执行了子类B的静态代码块");
}
{
System.out.println("执行了子类B的非静态代码块");
}
public B(){
System.out.println("执行了子类B的构造方法");
}
}
控制台输出(程序初始化顺序):
三、类的引用
1、主动引用(一定会初始化)
2、被动引用
/**
* @ClassName Demo02
* @Description 测试类的引用
* @Author xwd
* @Date 2018/10/23 21:58
*/
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException {
//主动引用:new一个类的对象
// People people = new People();
//主动引用:调用类的静态成员(除了final常量)和静态方法
// People.getAge();
// System.out.println(People.age);
//主动调用:使用java.lang.reflect包的方法对类进行反射调用
// Class.forName("pri.xiaowd.classloader.People");
//被动引用:当访问一个静态域时,只有真正声明这个域的类才会被初始化。
// System.out.println(WhitePeople.age);
//被动引用:通过数组定义引用,不会初始化
// People[] people = new People[10];
//被动引用:引用常量不会触发此类的初始化
System.out.println(People.num);
}
//主动调用:先启动main方法所在的类
// static {
// System.out.println("main方法所在的类在虚拟机启动时就加载");
// }
}
class People{
static int age = 3;
static final int num = 20;
static {
System.out.println("People被初始化了!");
}
public People() {
}
public static int getAge() {
return age;
}
public static void setAge(int age) {
People.age = age;
}
}
class WhitePeople extends People{
static {
System.out.println("WhitePeople被初始化了!");
}
}
四、类加载器的原理
1、类缓存
2、类加载器的分类
3、java.class.ClassLoader类
(1)作用:
(2)常用方法:
五、类加载器的代理模式
1、双亲委托机制
六、自定义类加载器
import java.io.*;
/**
* @ClassName FileSystemClassLoader
* @Description 自定义文件类加载器
* @Author xwd
* @Date 2018/10/24 9:23
*/
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;//根目录
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
/**
* @MethodName findClass
* @Descrition 加载类
* @Param [name]
* @return java.lang.Class<?>
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> loadedClass = findLoadedClass(name);//查询该类是否已经被加载过
if(loadedClass != null){ //该类已经被加载过了,直接返回
return loadedClass;
}else{ //该类还没有被加载过
ClassLoader classLoader = this.getParent();//委派给父类加载
try {
loadedClass = classLoader.loadClass(name);
} catch (ClassNotFoundException e) {
// e.printStackTrace();
}
if(loadedClass != null){ //父类加载成功,返回
return loadedClass;
}else{
byte[] classData = getClassData(name);
if(classData == null){
throw new ClassNotFoundException();
}else{
loadedClass = defineClass(getName(),classData,0,classData.length);
}
}
}
return loadedClass;
}
/**
* @MethodName getClassData
* @Descrition 根据类名获得对应的字节数组
* @Param [name]
* @return byte[]
*/
private byte[] getClassData(String name) {
//pri.xiaowd.test.A --> D:/myjava/pei/xiaowd/test/A.class
String path = rootDir + "/" + name.replace('.','/') + ".class";
// System.out.println(path);
InputStream is = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
is = new FileInputStream(path);
byte[] bytes = new byte[1024];
int temp = 0;
while((temp = is.read(bytes)) != -1){
baos.write(bytes,0,temp);
}
return baos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
if(baos != null){
baos.close();
}
if(is != null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}