[癜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)を実行します.例えば:
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を実行します.
->コンストラクタの残りの部分を実行します.
振り返ってみます.
--> 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」を印刷します.
振り返ってみます.
->陰的に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」を印刷します.
一つのクラスは、プログラムによって使用される前に、三つの準備作業(以下、クラス実行と総称する)を経験しなければならない.
->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」を印刷します.