クラスローディングの概要
Javaコード、タイプの接続された負荷、に初期化プロセスは、プログラム実行中に完了されます
タイプ:クラス、インタフェース(それ自体オブジェクト)、タイプは、動的プロキシとして、動作中に生成されてもよいです。一種類のruntingコンセプト
ロード:すでにクラスのバイトコードファイル(.classファイルのファイル)を既存する最も一般的な方法をされては、ディスクからメモリにロードされます。
接続:クラス間のクラス関係で上下セット、いくつかの相関処理のバイトコード検証が接続フェーズ中に完了されます
初期化:コピーされたいくつかの静的変数の場合
プロセスは、仕様に応じて、この順に限りません
より多くの可能性を高め、より高い柔軟性を提供します
それ自体は静的型付け言語ですが、機能や動的な性質の多くは、javaを作ります
クラスローダの深さ分析
Java仮想マシンとアプリケーション・ライフサイクル:以下の例では、Java仮想マシンは、ライフサイクルを終了します
でSystem.exit()メソッドの実装
プログラムが正常に終了します
中止され、実行中に例外やエラーが発生しました
オペレーティング・システム・エラーがJava仮想マシンを終了させるプロセスを引き起こしたので
クラスローディング、接続は、さらに説明初期設定します
ロード:バイナリデータのクラスを見つけ、ロード
クラスファイル(ファイルは必ずしも等、ネットワークデータベースのソースではないかもしれない)メモリにロード
- 接続
-
- 確認してください。必ずクラスがロードされていることを確認正しさを
-
準備:のクラスの静的変数のメモリを割り当てられ、初期化にデフォルト値。
オブジェクトクラスのこのインスタンスで作成されていません
//假设代码中有
class Test{
public static int a = 1;
}
//在准备这个阶段,虚拟机在准备阶段不会将1赋值给a,它会为a分配内存并且把0赋值给a
-
分析:クラスが直接参照シンボル参照に変換され、
シンボリックリファレンス:間接参照
直接引用:直接オブジェクトの基準点の位置をメモリ
- 初期化:クラスの静的変数の正しい初期値が与えられました
//假设代码中有
class Test{
public static int a = 1;
}
//在准备阶段,虚拟机在准备阶段不会将1赋值给a,它会为a分配内存并且把0赋值给a
//在初始化阶段,将a=0替换为a=1
アンクラスを使用します
クラスの使用
オブジェクトを作成し、使用
クラスアンロード
>メモリからの破壊、OSGiの
クラスローダ
アクティブとパッシブの使用を使用します
すべてのJava仮想マシンの実装は、「各クラスまたはインタフェースのJavaプログラムでなければならない最初の積極的な活用」彼らはときを初期化します
- Javaのプログラムのクラスの使用は2つに分割されています
- アクティブな使用(7種類)
クラスのインスタンスを作成します。
クラスまたはインタフェース、または静的変数割り当てのアクセス静的変数(ニーモニック:getstatic、putstatic)
静的クラスメソッドの呼び出し(ニーモニック:invokestatic)
- リフレクタ(例えばCalss.forName( "com.test.Test"))
クラスのサブクラスの初期化
クラスを初期化し、クラスが親クラスが親クラスを持っている場合、親クラスは、親クラスを初期化します持っている場合、それが初期化するまでになります
Javaのクラスが起動クラスとしてマークされている仮想マシン(Javaのテスト)
動的言語のサポートJDK1.7が提供を開始しました
分析結果REF_getStatic java.lang.invoke.MethodHandle、REF_putStatic、REF_invokeStaticハンドル対応するクラスが初期化されていない、初期化の例
- パッシブ使用
上記の例1に加えて、Javaクラスを使用する他の方法は、一種のと見られている受動的な使用クラスは発生しません、初期化を
クラスをロードするパッシブ使用、ちょうどされていない初期化
クラスのロード
クラスのロード
負荷は、バイナリデータメモリ読み出し、メソッド領域に配置され、ランタイムデータ領域への.classファイルクラスのクラスを参照し、指定がない(メモリにjava.lang.Classオブジェクトを作成しますオブジェクトが配置されているクラスの説明は、HotSpot仮想マシンがどの領域法)上のプロセスゾーンのクラスのデータ構造をパッケージするために使用され
負荷の.classは道をファイル
- 直接ロードローカルファイルシステム(最も一般的)から
- ネットワーク経由でダウンロードした.classファイル
- 郵便番号、瓶やアーカイブの他の種類の価格を聞いてから.Calssロードファイル
- 独自のデータベースからファイルを抽出.Calss
- Javaソースファイルを動的.calssファイルにコンパイル(実行時に作成するために、動的プロキシを、ウェブ開発者が使用されます)
例えば
eg1:
public class MyTest {
public static void main(String[] args) {
System.out.println(MyChild1.str1);
}
}
class MyParent1 {
public static String str1 = "hello world str1";
static {
System.out.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1 {
public static String str2 = "hello world str2";
static {
System.out.println("MyChiled1 static block");
}
}
//输出结果:
MyParent1 static block
hello world str1
以下のために、静的フィールド、唯一の直接フィールドのクラスが初期化されます定義します。したがって、本実施形態では、MyParent1のSTR1の直接使用は、それが、MyChild1を初期化しないであろう、MyParent1を初期化しますMyParent1が積極的に使用されているため。
「各クラスまたはインタフェースのJavaプログラムでなければならない上記のJava仮想マシンの実装のすべてを遵守する最初の積極的な活用、彼らは初期化時に」
eg2:
public class MyTest {
public static void main(String[] args) {
System.out.println(MyChild1.str2);
}
}
class MyParent1 {
public static String str1 = "hello world str1";
static {
System.out.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1 {
public static String str2 = "hello world str2";
static {
System.out.println("MyChiled1 static block");
}
}
//输出结果:
MyParent1 static block
MyChiled1 static block
hello world str2
サブクラスの初期化は、すべての親クラスが要件に初期化されている本実施形態では、MyChild1のSTR2の直接の使用は、それが初期化さMyChild1ますが、アクティブの使用により、サブクラスクラスを初期化するために、見ることができます親クラスが初期化されます。(各クラスは一度だけ初期化されます)
したがって、本実施形態では、出力操作を行う、初期化MyParent1 MyChild1に初期化されるMyChild1.str2
eg3:
//执行主类的 VM arguments 中 添加 -XX:+TraceClassLoading
//打印类加载信息
public class MyTest {
public static void main(String[] args) {
System.out.println(MyChild1.str1);
}
}
class MyParent1 {
public static String str1 = "hello world str1";
static {
System.out.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1 {
public static String str2 = "hello world str2";
static {
System.out.println("MyChiled1 static block");
}
}
//输出结果
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
...
[Loaded java.security.UnresolvedPermission from shared objects file]
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded cn.lillcol.classloader.MyTest from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded sun.launcher.LauncherHelper$FXHelper from shared objects file]
[Loaded java.lang.Class$MethodArray from shared objects file]
[Loaded java.lang.Void from shared objects file]
[Loaded cn.lillcol.classloader.MyParent1 from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded cn.lillcol.classloader.MyChild1 from file:/E:/lteworkspace/gaSvr/target/classes/]
MyParent1 static block
hello world str1
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
最初のクラスはjava.lang.Objectのロードされ、それはすべてのクラスの親であります
MyChild1は初期化されていませんが、仮想マシンはまだMyChild1をロードしたが、
そして、我々は、関連するクラスのロード順のMyTest、MyParent1、MyChild1、書き込みのJava仮想マシンのクラスへのMyTestクラスのスタートは、起動クラスとしてマークされているが
eg4:
public class MyTest {
static {
System.out.println("MyTest static block");
}
public static void main(String[] args) {
System.out.println(MyChild1.str1);
}
}
class MyParent1 {
public static String str1 = "hello world str1";
static {
System.out.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1 {
public static String str2 = "hello world str2";
static {
System.out.println("MyChiled1 static block");
}
}
//输出结果:
[Loaded cn.lillcol.classloader.MyTest from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded sun.launcher.LauncherHelper$FXHelper from shared objects file]
[Loaded java.lang.Class$MethodArray from shared objects file]
[Loaded java.lang.Void from shared objects file]
MyTest static block
[Loaded cn.lillcol.classloader.MyParent1 from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded cn.lillcol.classloader.MyChild1 from file:/E:/lteworkspace/gaSvr/target/classes/]
MyParent1 static block
hello world str1
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
MyParent1、MyChild1、前のMyTest負荷順序は、Java仮想マシンのクラスが起動クラスとしてマークされ始めます
eg5:
public class MyTest2 {
public static void main(String[] args) {
System.out.println(MyParent2.str2);
}
}
class MyParent2 {
public static final String str2 = "hello world";
static {
System.out.println("MyParent2 static block");
}
}
//输出结果
hello world
定数コンパイル時には、ために入金されます。この一定のメソッドを呼び出すところ、クラスの定数プールインチ
本質的には、クラスが直接クラスの定数の定義を参照していないので、呼び出し、定数定義されたクラストリガされませんの初期化を
注意:これは、を意味し、一定STR2に保存されているMyTest2定数プール MyTest2とMyParent2はどんな関係を持っていた後、さらにはMyParent2の.classファイル削除のこの時点では重要ではありません。
eg6:
public class MyTest3 {
public static void main(String[] args) {
System.out.println(MyParent3.str3);
}
}
class MyParent3{
public static final String str3= UUID.randomUUID().toString();
static {
System.out.println("MyParent3 static block ");
}
}
//输出结果:
MyParent3 static block
62322324-7b63-49c8-a8c4-f6607421f7ff
あなたが一定の値がコンパイル時に決定することができない場合は、その値が一定のプールにクラスを呼び出すことはありません
プログラムを実行しているときに、この時点では、イニシアチブは初期化され、明らかにこのクラスにつながり、このクラスの定数を使用することにつながります
eg7:在终端下用 javap -c 命令反编译MyTest2的.calss文件
javap -c MyTest2
#输出结果
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
public cn.lillcol.classloader.MyTest2();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22 // String hello world
5: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
ニーモニック:LDCはスタックにプッシュされ、または定数プールからString型定数値の整数、フロートを示します
eg8:将代码作如下修改
public class MyTest2 {
public static void main(String[] args) {
System.out.println(MyParent2.s);
}
}
class MyParent2 {
public static final String str2 = "hello world";
public static final short s = 7;
static {
System.out.println("MyParent2 static block");
}
}
//输出:
7
//反编译结果:
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
public cn.lillcol.classloader.MyTest2();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 7
5: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
8: return
}
ニーモニック:bipushはスタックにプッシュされ定数プールから1バイト(-128--127)一定の値を示します
eg9:将代码作如下修改
public class MyTest2 {
public static void main(String[] args) {
System.out.println(MyParent2.i);
}
}
class MyParent2 {
public static final String str2 = "hello world";
public static final short s = 7;
public static final int i = 128;
static {
System.out.println("MyParent2 static block");
}
}
//输出:
128
//反编译结果:
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
public cn.lillcol.classloader.MyTest2();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: sipush 128
6: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
9: return
}
ニーモニック:sipushはスタックにプッシュされ定数プールから1バイト(-32768--32767)一定の値を示します
eg10:将代码作如下修改
public class MyTest2 {
public static void main(String[] args) {
System.out.println(MyParent2.m);
}
}
class MyParent2 {
public static final String str2 = "hello world";
public static final short s = 7;
public static final int i = 128;
public static final int m = 0;
static {
System.out.println("MyParent2 static block");
}
}
//输出:
0
//反编译结果:
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
public cn.lillcol.classloader.MyTest2();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_0
4: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
7: return
}
ニーモニック:iconst_0 1スタック(iconst_m1 - iconst_5)から押し出さINT定数プールのタイプを示します
位置保存ニーモニック:rt.jar内のjdk
eg11:
public class MyTest4 {
public static void main(String[] args) {
MyParent4[] myTest4s = new MyParent4[1];
System.out.println(myTest4s.getClass());
MyParent4[][] myTest4s1 = new MyParent4[1][1];
System.out.println(myTest4s1.getClass());
System.out.println(myTest4s.getClass().getSuperclass());
System.out.println(myTest4s1.getClass().getSuperclass());
int[] ints=new int[1];
System.out.println(ints.getClass());
System.out.println(ints.getClass().getSuperclass());
}
}
class MyParent4{
static {
System.out.println("MyParent4 static block");
}
}
//输出:
class [Lcom.aaa.test.MyParent4;
class [[Lcom.aaa.test.MyParent4;
class java.lang.Object
class java.lang.Object
class [I
class java.lang.Object
例えばアレイは、そのタイプを動的動作中にJVMによって生成され、クラスとして表さ[Lcom.aaa.test.MyParent4、このフォーム、動的に生成された親クラスの型がjava.lang.Objectのです。
アレイについては、Javadocは、しばしば縮小次元のアレイ型後に、実際には、部品を構成する配列要素と呼びます。
eg12:
int[] ints=new int[1];
System.out.println(ints.getClass());
short[] showts=new short[1];
System.out.println(showts.getClass());
boolean[] booleans=new boolean[1];
System.out.println(booleans.getClass());
char[] chars=new char[1];
System.out.println(chars.getClass());
byte[] bytes=new byte[1];
System.out.println(bytes.getClass());
float[] floats=new float[1];
System.out.println(floats.getClass());
double[] doubles=new double[1];
System.out.println(doubles.getClass());
//输出:
class [I
class [S
class [Z
class [C
class [B
class [F
class [D
ニーモニック:
anewarray:基準(例えば、クラス、インタフェース、アレイなど)タイプの配列、およびスタックに基準値を生成する手段
ewarray:プリミティブを作成スタックに指定された配列の型(例えば、整数、浮動小数点、文字、など)、および基準値を示し
JVM引数
-XX:+<option>,表示开启option选项
-XX:-<option>,表示关闭option选项
-XX:<option>=<value>,表示将option选项的值设置value
+、 - なぜならデフォルトでオンまたはオフにいくつかのパラメータ
この記事張ロング学習教師の深い理解と経験がJVMを指摘し、ソースを明記してください!!!