1. Foo.class 代表什么
Whenever we compile any Java file, the compiler will embed a public, static, final field named class
, of the type java.lang.Class
, in the emitted byte code. Since this field is public, we can access it using dotted notation
JVM类加载过程划分为装载,链接和初始化。装载和链接过程完成后,即将字节码转换为为Class对象。初始化过程会执行类中静态初始化代码,静态属性的初始化。
Foo.class会生成 Class 的对象,但它并没有进行初始化
Class.forName("com.hong.classLoader.Foo"会进行初始化,因为它调用的
Class<T> java.lang.Class.forName(String name, boolean initialize, ClassLoader loader)
initialize为true
让ClassLoader去装载Foo.class 字节码 返回代表Foo这个类的 Class对象
System.out.println(ClassLoaderDemo.class.hashCode());
System.out.println(Class.forName("com.hong.ClassLoaderDemo").hashCode());
System.out.println(ClassLoaderDemo.class.getClassLoader());
System.out.println(Class.forName("com.hong.ClassLoaderDemo").getClassLoader());
这两个产生的 Class对象是一样的,说明只装载一次
Class里有存加载它们的ClassLoader,加载他们的ClassLoader也是同一个
2. 为什么普通的类是被 AppClassLoader加载 ?
http://www.iteye.com/topic/83978
-----BootStrap类加载器 加载JRE/lib
-----ExtClassLoader 加载 JRE/lib/ext
-----AppClassLoader 加载ClassPath/
System.out.println(System.getProperty("sun.boot.class.path"));
System.out.println(System.getProperty("java.ext.dirs"));
System.out.println(System.getProperty("java.class.path"));
3.一个相同的类被两个ClassLoader加载,有什么好处
一个Application server避免两个应用相互干扰,比如tomcat下放几个工程,tomcat启动的时候把他们启动起来用不同的ClassLoader 就不会相互干扰
JVM通过类的全限定名和类加载器来标识一个被加载的类
4.不同classloader里的类能交互吗
if class Foo is loaded by class loader B, and Foo depends on class Baz, then class Baz must be loadable by either class loader A or B. If Baz is only visible to class loader C or D, then a ClassNotFoundException will occur
5.调用static方法要创建对象吗?
不用,但要装载类,会对Class对象进行初始化
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
- T is a class and an instance of T is created.
- T is a class and a static method declared by T is invoked.
- A static field declared by T is assigned.
- A static field declared by T is used and the reference to the field is not a compile-time constant http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313](§15.28). References to compile-time constants must be resolved at compile time to a copy of the compile-time constant value, so uses of such a field never cause initialization
反射调用类的方法也会初始化
测试代码:
/**
*
*/
package com.hong.classLoader;
import java.util.Random;
/**
* @author Administrator
*
*/
class Initable {
static final int staticFinal = 47;
static final int staticFinal2 = ClassInitialization.rand.nextInt(100);
Initable() {
System.out.println("Initable construct invoke");
}
static {
System.out.println(" Initable static invoke");
}
}
class Initable2 {
static int staticNoFinal = 147;
static {
System.out.println("Initialization Initable2");
}
}
class Initable3 {
static int staticNoFinal = 74;
static {
System.out.println("Initialization Initable3");
}
}
public class ClassInitialization {
public static Random rand = new Random(47);
public static void main(String[] args) throws ClassNotFoundException {
Class<Initable> initable = Initable.class; // 不会引起初始化
Class<?> initable2 = Class.forName("com.hong.classLoader.Initable",
false, ClassInitialization.class.getClassLoader());// 不会引起初始化
System.out.println(initable.hashCode());
System.out.println(initable2.hashCode());
System.out.println(ClassInitialization.class.getClassLoader());// classloader
// 是同一个
System.out.println("after creating Initable reference");
System.out.println(Initable.staticFinal); // 引用编译期常量不会引起初始化
System.out.println(Initable.staticFinal2); // 引起初始化
System.out.println(Initable2.staticNoFinal); // 引用非编译期常量会引起初始化
Class initable3 = Class.forName("com.hong.classLoader.Initable3"); // 默认会引起初始化
System.out.println("after creating Initable3 reference");
System.out.println(Initable3.staticNoFinal);// 前面已经初始化此处不用再初始化
}
}
参考:http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html#44459
http://onjava.com/pub/a/onjava/2005/01/26/classloading.html?page=1