类加载顺序 Class对象

知识:

我们都知道程序都是运行在JVM上的,而且,JVM的加载机制是RTTI(Run-Time Type Identification,通过运行时类型识别),那么JVM是怎么加载类以及生成加载对象的呢。

当我们编写并且编译了一个新类,就会产生一个Class对象,这个对象用来创建所有的“常规对象”,例如我们新NEW的对象。这时,这个类是没有加载到JVM中的。

第一次使用类时,才将类加载到JVM中,使用到了JVM的类加载器。

程序使用类的时候,JVM的类加载器会去检查这个类的Class对象是否已经被加载,如果尚未加载就会去.class文件中加载。如果已经加载,就不需要再加载一次了。

初始化顺序如下:

  1. 静态初始化:只在类加载的时候初始化一次。之后不管生成多少类的对象都不再初始化。
  2. 成员变量:类在生成对象的时候,必须先初始化类的成员变量。所以,在调用类的构造方法之前,类的成员变量已经被初始化。
  3. 非静态代码块{···}:也是在调用类的构造方法之前执行。
  4. 成员变量和非静态代码块的初始化顺序,按照代码出现的顺序初始化。
  5. 构造方法

好了,看程序:

class Candy{
    
    
    
    static int i=0;
    print p=new print();
    {
        i=1;
        System.out.println("Loading candy not static");
        
    }
    
    static{
        i=2;
        System.out.println("Loading candy static");    
    }
    
    public Candy(){
        
        System.out.println("Loading candy()");
        System.out.println("i="+i);
        
    }
    
    
}

class print{
    
    print(){        
        System.out.println("print !!!!!!!");
    }
}

public class ObjectClass {
    
    public static void main(String args[]){
        
        new Candy();
        
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~1");
        
        new Candy();
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~2");
        
    }

}

输出如下:

Loading candy static
print !!!!!!!
Loading candy not static
Loading candy()
i=1
~~~~~~~~~~~~~~~~~~~~~~1
print !!!!!!!
Loading candy not static
Loading candy()
i=1
~~~~~~~~~~~~~~~~~~~~~~2


注:static子句是类加载时执行的语句

所以可以看到,Loading candy static这句输出只被打印了一次。证明,JVM只加载类一次。

其次,我们可以看出,static子句,成员变量,构造块(用{}括起来的程序),构造方法的加载顺序依次是:

static子句首先被加载,但是只加载一次。其次是成员变量,构造块,(这里需要说明的是,如果成员变量和构造块互换位置,那么输出时语句也将互换)

最后是构造方法。


Class.forName()

这里我们引入一个比较特别的用法Class.forName().他的作用是,在JVM中,如果类还未加载就去加载他,返回的是一个Class对象的引用。

public static void main(String args[]){
		
		//new Candy();
		try{
			
			Class.forName("leet.Candy");
		}catch(ClassNotFoundException e){
			
			System.out.println("could not found candy");
		}
		System.out.println("~~~~~~~~~~~~~~~~~~~~~~1");
		
		new Candy();
		System.out.println("~~~~~~~~~~~~~~~~~~~~~~2");
		try{
			
			Class.forName("leet.Candy");
		}catch(ClassNotFoundException e){
			
			System.out.println("could not found candy");
		}

		System.out.println("~~~~~~~~~~~~~~~~~~~~~~3");

		
	}

输出:

Loading candy static
~~~~~~~~~~~~~~~~~~~~~~1
Loading candy not static
Loading candy()
i=1
~~~~~~~~~~~~~~~~~~~~~~2
~~~~~~~~~~~~~~~~~~~~~~3


Class.forName()返回的是类的引用,如果JVM中没有加载这个类,就会去加载。如果只是生成一个对象的引用,我们可以发现,其实JVM什么也没干。

public class ObjectClass {
	
	public static void main(String args[]){
		
		Candy c;

	}

}

这样的话,什么都不会输出。

你可能感兴趣的:(java)