java - Static 标识的字段或者是代码块,真的是在类加载的时候初始化的吗?
PHPz
PHPz 2017-04-18 10:52:20
0
8
693
class AAA {
    static {
        System.out.println("class AAA static block println"); // 并没有打印此句
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("hello world!");
    }
}

一直以来都以为 static 标识的代码块或者是字段,都是在类加载的时候就被执行或者赋值了,但是这么一看....感觉自己的世界观都要被刷新了。

所以此处是类没有被加载吗?还是说我们一直以来认为的,静态代码块、字段都在类加载的时候被初始化的,这个观点是错误的?

在《深入理解Java虚拟机:JVM高级特性与最佳实践 第2版》中找到一些线索,如下图:

所以,照这么说,是在第一次主动访问该类的时候执行?小弟好生迷惑啊....大家快说说你们的观点

PHPz
PHPz

学习是最好的投资!

全員に返信(8)
左手右手慢动作

クラスの初期化とオブジェクトの初期化。

static に含まれるコード ブロックと変数は、クラスが初期化されるときにのみ実行されます。また、初期化の 5 つの条件もわかります。

追加説明をわかりやすくお願いします。
まず第一に、これらを同じ .java ファイルに入れても、コンパイル後は依然として 2 つの異なるクラス ファイルであることに変わりはありません。信じられない場合は、対応するパッケージの下に生成された .class ファイルを見てください。ビン。
2 番目に、クラスが初期化されると、クラスの静的変数が初期化され、静的コード ブロックが実行されます。そのため、仮想マシンでは new、getstatic、putstatic 命令の使用、main 関数が配置されているクラス、リフレクション、親クラスなどの 5 つの初期化条件を規定しています。ただし、これら 5 つの状況を除いて、クラスの初期化をトリガーすることはできません。コードに示されているように、Main.class には、AAA.class に関する呼び出しや親子関係やリフレクションはありません。したがって、AAA.classは当然初期化されません。

Java クラスのロードプロセスについては別のブログを読むことができます

わかりますか?

いいねを押す +0
阿神

-XX:+TraceClassLoading
これを追加すると、AAAがロードされていないことがわかります

いいねを押す +0
洪涛

ここで議論する必要がある 2 つの概念があります:

  1. クラスロードメカニズム

  2. Java、コンパイラー、バイトコード、JVM の仕様と実装。

クラスの読み込みはクラス ローダー (クラスローダー) を通じて完了します。具体的な読み込み戦略は、一般的に、次の 2 つのタイプに分けられます。

  1. ハングリーロード。他のクラスによって参照されている限りロードします。

  2. 遅延ロード、クラスがアクセスされたときにのみロードされます。

Java、コンパイラー、バイトコード、JVM には独自の仕様があり、その仕様を通じて連携して動作します。

コンパイルボタンは、Java コードを標準化されたバイトコード ファイルにコンパイルします。JVM がクラスをロードするときに、各クラス (外部クラス、内部クラス、匿名クラス) が個別のバイトコード ファイル (クラス ファイル) にコンパイルされます。クラスファイル。

コードに戻ります:

Java レイヤーでは、2 つのクラス AAA と Main を 1 つのファイルに配置します。コンパイル後、コンパイラーは 2 つのクラス ファイル AAA.class と Main.class を生成します。

2 つのクラスはコード構成の点では一緒ですが、コンパイル後は独立しており、Main は AAA を参照しないため、どのクラス ロード方法が使用されても、クラス AAA のロードはトリガーされず、クラス AAA のロードもトリガーされません。 AAA で静的コード ブロックを実行します。

いいねを押す +0
左手右手慢动作

上の階の熱心なネチズンの皆様、ご回答いただき誠にありがとうございました!

確認する

実際、AAA クラスはロードされず、Main クラスのみがロードされます (質問のスクリーンショット: 4 番目の初期化条件、メイン クラスは jvm によって自動的にロードされます)

リーリー

結論

クラス内の 静的フィールド|コード ブロック は、クラスがロードされるときに実際に初期化または実行されます。

拡張機能

クラスがjvmによってロードされたかどうかを確認するにはどうすればよいですか?

これは私も苦労している問題です。最初は javac 命令,类就被 jvm 加载了,其实不然,该命令只是将 .java 文件转化成 jvm 能读懂的 .class ファイルを実行するだけの問題だと思いました。

それでは、クラスが jvm によってロードされたかどうかをどうやって知ることができるのでしょうか?
「Java 仮想マシンの深い理解: JVM の高度な機能とベスト プラクティス 第 2 版」とネチズンからの熱心な回答によると、いつロードされるかを規定する明確なタイミングはありません。

でも! jvm クラスが初期化されるタイミングを明確に規定しています - 質問文のスクリーンショットにある 4 種類です!クラスのロードはクラスの初期化よりも優先されるため、ここでは、これらの状況がクラスのロードをトリガーする条件であると一時的に考えることができます。

私の兄は無知で間違ったことを要約しているので、修正してください。ありがとう

いいねを押す +0
PHPzhong

Main.java と AAA.java を同じフォルダーに配置します。

main関数に記述します

リーリー

実行

いいねを押す +0
大家讲道理

mainメソッドを実行するとMainクラスのみがロードされますが、MainクラスではAAAクラスは使用されず、AAAとMainの2つのクラスを同じに書いても意味がありません。ファイルはそれらを同時にロードします

いいねを押す +0
大家讲道理

AAA クラスは他では新しいものではなく、それに対応して静的フィールドを取得または設定したり、静的メソッドを呼び出したりすることもありません。
そのため、自動的には初期化されません。

いいねを押す +0
迷茫

2つのクラスに配置されており、publicとして宣言されたクラスのメインのクラスは使用されず、初期化されることもありません

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート