赞
踩
- class SuperClass{
- static{
- System.out.println("SuperClass init!");
- }
- public static int value = 123;
- }
-
- class SubClass extends SuperClass{
- static{
- System.out.println("SubClass init!");//子类中引用父类的静态字段,不会导致类初始化
- }
- }
-
- public class Test {
- public static void main(String[] args) {
- System.out.println(SubClass.value);
- }
- }
- class ConstClass{
- static{
- System.out.println("ConstClass init!");
- }
- public static final String HELLOWORLD = "hello world";
- }
-
- public class Test {
- public static void main(String[] args) {
- System.out.println(ConstClass.HELLOWORLD);
- }
- }
(1)通过一个类的全限定名来获取其定义的二进制字节流。
(2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
(3)在内存中生成一个代表这个类的java.lang.Class对象(并没有明确规定是在java堆中,对于HotSpot虚拟机来说,Class对象比较特殊,它虽然是对象,但是存放在方法区里面),作为对方法区中这些数据的访问入口。
对于(1),并没有指明二进制字节流的获取途径,也即不一定都是从一个Class文件中获取,还可以从如下方式获取:
- public class Test {
- static{
- i = 0;//可以给变量赋值,编译通过
- System.out.println(i);//编译不通过!!不能进行访问后面的静态变量
- }
- static int i =1;
- }
任意一个类,都需要由加载它的类加载器和这个类本身共同确定其在Java 虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达的更通俗一些:比较两个类是否相等,只有在这两个类是同一个类加载器加载的前提下才意义。否则,即使这两个类来自同一个Class文件,被同一个虚拟机加载,但只要加载他们的类加载器不同,那这两个类就必定不相等。
这里的“相等”,包括代表类的 Class 对象的equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果,也包括 instanceof 关键字对对象所属关系判定等情况。下面代码演示了不同类加载器对 instanceof 关键字运算的结果的影响。
- public class ClassLoaderTest {
- public static void main(String[] args) throws Exception {
- ClassLoader myLoader = new ClassLoader() {
- @Override
- public Class<?> loadClass(String name)
- throws ClassNotFoundException {
- try {
- String fileName = name.substring(name.lastIndexOf(".") + 1)
- + ".class";
- InputStream is = getClass().getResourceAsStream(fileName);
- if (is == null) {
- return super.loadClass(name);
- }
- byte[] b = new byte[is.available()];
- is.read(b);
- return defineClass(name, b, 0, b.length);
- } catch (IOException e) {
- throw new ClassNotFoundException(name);
- }
- }
- };
-
- Class c = myLoader.loadClass("org.bupt.xiaoye.blog.ClassLoaderTest");
- Object obj = c.newInstance();
- System.out.println(obj.getClass());
- System.out.println(ClassLoaderTest.class);
- System.out.println(obj instanceof ClassLoaderTest);
-
- }
- }
从虚拟机的角度来讲,只存在两种不同的类加载器:
一种是启动类加载器(Bootstrap ClassLoader),这个类加载器用 C++ 语言实现, 是虚拟机自身的一部分:
另一种就是所有其它的类加载器, 这些类加载器用Java 语言实现,独立于虚拟机外部,并且全都继承与抽象类 java.lang.ClassLoader。
从Java 开发人员的角度来看,类加载器还可以划分的更细致一些,绝大多数Java 程序都会用到以下3种系统提供的类加载器:
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- synchronized (getClassLoadingLock(name)) {
- // 首先检查类是否已经被加载过
- Class c = findLoadedClass(name);
- if (c == null) {
- long t0 = System.nanoTime();
- try {
- if (parent != null) {
- // 调用父类加载器加载
- c = parent.loadClass(name, false);
- } else {
- c = findBootstrapClassOrNull(name);
- }
- } catch (ClassNotFoundException e) {
- // ClassNotFoundException thrown if class not found
- // from the non-null parent class loader
- }
-
- if (c == null) {
- // If still not found, then invoke findClass in order
- // to find the class.
- //父类加载器无法完成加载,调用本身的加载器加载
- long t1 = System.nanoTime();
- c = findClass(name);
-
- // this is the defining class loader; record the stats
- sun.misc.PerfCounter.getParentDelegationTime().addTime(
- t1 - t0);
- sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(
- t1);
- sun.misc.PerfCounter.getFindClasses().increment();
- }
- }
- if (resolve) {
- resolveClass(c);
- }
- return c;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。