-------------------------------------------------android培训、java培训期待与您交流!----------------------------------
一、概述
1.java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap(JRE/lib/rt.jar)、ExtClassLoader(JRE/lib/ext/*.jar)、AppClassLoader(ClassPath指定的所有jar或目录)
2.类加载器也是java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须第一个类加载器不是不是java类,这正是BootStrap
3.Java虚拟机的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指一个父级装载器对象或者默认采用系统类装载器为其父级类加载
4.当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
1)首先当前线程的类加载器去加载线程的第一个类
2)如果类A中引用了类B,Java虚拟机将使用加为A的类装载器来加载类B
3)还可以直接调用ClassLoder.loadClass()方法来指定某个类加载器去加载某个类
5.每个类加载器加载类时,又先委托给其上级类加载器
当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个?
二、类的加载过程
public class SingerClass
{
private static SingerClass singer=new SingerClass();
public static int count1;
public static int count2=0;
private SingerClass()
{
System.out.println("加载中……");
count1++;
count2++;
}
public static SingerClass newInstence()
{
return singer;
}
}
public class SingerTest
{
public static void main(String[] args)
{
SingerClass singer=SingerClass.newInstence();
System.out.println(SingerClass.count1);//1
System.out.println(SingerClass.count2);//0 why?
//for
//(1)类的主动使用,会加载类
/*
* 1.创建类的实例
* 2.访问某个类或接口的静态变量,或者对该静态变量赋值
* 3.调用类的静态方法
* 4.反射(Class.forName("com.sun.test")
* 5.初始化一个类的子类
* 6.Java虚拟机启动时被标明为启动的类
*/
//(2)类的执行
/*
* 1.类加载器来加载,加载到方法区
* 2.检查类的文件的正确性
* 3.类静态字段的默认初始
* 4.类静态字段的正确默认(用户赋的值)
* 5.在堆中生成对应Class对象
*/
}
}
//相关final加载
public class FinalTest1
{
public static void main(String[] args)
{
System.out.println(Final1.x);
//System.out.println(Final1.b);
//System.out.println(Final1.c);
//总之:调用的如不确定,就要初始块
}
}
class Final1
{
public static int a=12;
public static final int x=2;
public static final int b;
public static final int c=new Random().nextInt(100);
//下面不会被执行,因为是final类型,那么它的值2就确定了
//但外部调用b,不确定就执行
static
{
b=1;
System.out.println("我执行了!");
}
}
三、自定义类加载
//自定义类加载器继承ClassLoader类
public class UserLoader extends ClassLoader
{
private String name;
private String path="D:\\";
private String className=".class";
public UserLoader(String name)
{
super();
this.name=name;
}
public UserLoader(ClassLoader classLoader,String name)
{
super(classLoader);
this.name=name;
}
public String getPath()
{
return path;
}
public void setPath(String path)
{
this.path = path;
}
//先执执行loadClass方法,首先找系统加载器,如果不能加载就找根加载器,再不能就使用findClass找到的Class,最后不能就报错
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
byte[] b=loadClassData(name);
return defineClass(name, b, 0, b.length);
}
//转换为字节
private byte[] loadClassData(String name)
{
byte[] b=null;
InputStream in=null;
ByteArrayOutputStream baos=new ByteArrayOutputStream();
try
{
name=name.replace(".", "\\");
in=new FileInputStream(new File(path+name+className));
int len=0;
while(-1!=(len=in.read()))
{
baos.write(len);
}
b=baos.toByteArray();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
in.close();
baos.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
return b;
}
@Override
public String toString()
{
return this.name;
}
public static void main(String[] args)
{
UserLoader ul=new UserLoader("ul");
ul.setPath("E:\\ClassPath\\");
//指定ul作为父类加载器,如果ul加载不了就交给了系统加载器
UserLoader ul1=new UserLoader(ul, "ul1");
ul1.setPath("E:\\Class\\");
try
{
//本类由系统加载器加载,ClassTest由用户加载器加载 Class<?> testClass=ul1.loadClass("ClassTest");
Object o=testClass.newInstance();
//ClassTest test=(ClassTest)o;
ul=null;//类的加载器卸载(只有用户加载器可以)
//但Class还是可以用的
Field[] fields=testClass.getFields();
System.out.println(fields[0].getInt(o));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
-------------------------------------------------android培训、java培训期待与您交流!----------------------------------