[癜0 x 0023]class loading:Frther discussion involving steps of instance creation


本文は[萼0 x 0001]、[落0 x 0008]、[33852;0 x 000 B]に対して統一的に要約します.
 
一つのクラスは、プログラムによって使用される前に、三つの準備作業(以下、クラス実行と総称する)を経験しなければならない.
->1.loading
->2.linking
      --> 2.1 veriflication
      --> 2.2 preparation
      --> 2.3 resolution(optional)
->3.inintialization
 
私たちが使用しているloading(ローディング)は、上記の3つのステップを指しています.
 
loadingとは.classファイルからクラスのbinary representation(クラスのクラスのクラスのオブジェクト)を読み出すプロセスのことです.
verficationプロセスは、binary representationの構造が正しいかどうかを検証する.
preparationプロセスは、クラスのstatic fieldアプリケーション空間であり、デフォルト値を付与しながら、クラスのいくつかの内部データ構造(例えば、方法リスト)のための空間を申請する.
resolution過程分析類における引用.resolutionプロセスはoptionalのプロセスであり、resolutionプロセスには異なるloading戦略があり得る.例えば、reolve class Aの場合、class Aにはclass Bの引用があり、その時にはすぐにclass Bをロードしてもいいし、do nothingもできます.
initializationプロセスは、static initializerとinitializer for static field(i.e.static variable initializer)を実行します.例えば:
private static int i = 5; //static variable initializer

//static initializer
static
{
	......
}
以下はinitialization段階で実行されていないコードです.
private int i = StaticFunction(); //      static  ,  field  static,    static variable initialzer

//    static field   ,   initializer    static,      static initializer
{
	StaticField = xxx;
	......
} 
 
loadingとlinkingプロセスはimplement-dependentであり、追跡と閲覧に不便であるため、loadingとlinkingのトリガ条件はしばらく議論しない.以下はinitializationを重点的に検討します.
initialization三原則:
->1. トリガーの原則:以下の3つのシーンが実行される前にイニシャルをトリガします.
      --> 作成クラスの例(constractor Class.newInstance()
      --> 呼び出しの種類のstatic方法(constructorを含む)
      --> finalではないstatic field is used or assigned
->2.親の原則:子類initializationの前に、そのdirect父類はinitialization、andが必要です. ドit recursively.(p.s.クラスが実現するインターフェースはinitializationを必要とせず、クラスが実現するインターフェースの親インターフェースも必要としない)
->3.誘発原則:子種initializationが父類のinitializationを誘発した場合、父類がまだloadingとlinkingを持っていない場合、父類のloadingとlinkingも誘発されると思います.
 
ここで強調したいのは、loading、linking、initializationはいずれもクラスの行為です.したがって、initializationはstaticです.インスタンスの作成は対象行為です.
 
constructorが実行するプロセス:
->this()or super()を実行します.
->initializerとnon-static variable initiazerを実行します.
->コンストラクタの残りの部分を実行します.
 
振り返ってみます.
//@file Beetle.java

import static java.lang.System.out;

class Insect 
{
	private int i = 1;
	protected int j;
	private static int x1 = printInit("static Insect.x1 initialized");
	
	Insect() 
	{
		out.println("Insect constructor");
		out.println("i = " + i + ", j = " + j + ", x1 = " + x1);
		this.j = 2;
	}
	
	static int printInit(String s) 
	{
		out.println(s);

		return 3;
	}
}

public class Beetle extends Insect 
{
	private int k = printInit("Beetle.k initialized");
	private static int x2 = printInit("static Beetle.x2 initialized");
	
	public Beetle() 
	{
		out.println("Beetle constructor");
		out.println("j = " + j + ", k = " + k + ", x2 = " + x2);
	}
 
	public static void main(String[] args) 
	{
		Beetle b = new Beetle();
	}
}
//output:
/*
	static Insect.x1 initialized
	static Beetle.x2 initialized
	Insect constructor
	i = 1, j = 0, x1 = 3
	Beetle.k initialized
	Beetle constructor
	j = 2, k = 3, x2 = 3
*/
->Insectにアクセスするmain方法は、staticであり、Beetleのloading、linking、initializationを誘発し、initializationはInsectのloading、linking、initializationを誘発する.
      --> Insectのinitialization、prvate static int x 1(=3)を実行し、「static Insect.x 1 initialized」を印刷します.
      --> Beetleのinitialization、prvate static int x 2(=3)を実行し、「static Beetle.x 2 initialized」を印刷します.
->mainに入ると、constructorが見つかりました.
->隠しコールsuper()を呼び出して、Insectのconstructに移動します.
      --> Insectはすでにloading、linkingとinitializationを実行して、直接non-static variable initializerを実行して、prvate int i(=1)とprotected int j(=0 by default)を初期化します.
      --> Insect constructの残りの部分を実行して、「Insect construct」と「i=1,j=0,x 1=3」を印刷してj=2
->Beetleのnon-static variable initializerを実行し、prvate int k(=3)を初期化し、「Beetle.k initialized」を印刷します.
->Beetle constructorの残り部分を実行し、「Beetle constructor」と「j=2,k=3,x 2=3」を印刷します.
 
振り返ってみます.
class Glyph
{
	void draw() 
	{ 
		System.out.println("Glyph.draw()");
	}
	
	Glyph()
	{
		System.out.println("Glyph constructor");
		draw();
	}
}	

class RoundGlyph extends Glyph 
{
	private int radius = 1;

	RoundGlyph(int r)
	{
		System.out.println("before assignment in constructor, radius = " + radius);
		radius = r;
		System.out.println("RoundGlyph constructor, radius = " + radius);
	}
	
	void draw()
	{
		System.out.println("RoundGlyph.draw(), radius = " + radius);
	}
}	

public class PolyConstructors
{
	public static void main(String[] args)
	{
		new RoundGlyph(5);
	}
}
//Output:
/*
	Glyph constructor
	RoundGlyph.draw(), radius = 0
	before assignment in constructor, radius = 1
	RoundGlyph constructor, radius = 5
*/
->PolyControuctorsのmainメソッドにアクセスして、loading、linking PolyControuctors、mainに入ると、RoundGlyphコンストラクタが見つかりました.
->陰的にsuperを呼び出して、「Glyph constructor」を印刷して、RoundGlyphのdrawを実行して、「RoundGlyph.draw()、radius=0」を印刷します.
->RoundGlyphを実行するnon-static variable initializer,radius=1
->RoundGlyphコンストラクタの残りの部分を実行し、「before assignment in constructor、radius=1」を印刷し、radius=5、「RoundGlyph constructor、radius=5」を印刷します.