免責事項:これについての明示的なOracleの声明を読んだことがないので、確実に言うのは難しいですが、これが理由だと思います:
Java バイト コードを見ると、他の命令について同じ質問をすることができます。スタックに2 つの s をプッシュし、その直後にint
それらを 1 つとして扱うと、検証者が停止するのはなぜですか? long
(試してみてください。停止します。)これを許可することで、同じロジックをより小さな命令セットで表現できると主張できます。(この議論をさらに進めると、1 バイトはあまりにも多くの命令を表現できないため、Java バイト コード セットは可能な限り削減する必要があります。)
もちろん、理論的には、int
s とs をスタックにプッシュするためのバイト コード命令は必要なく、メソッド呼び出しを表現するためにlong
2 つの命令を必要としないという事実については正しいですINVOKESPECIAL
。メソッドはそのメソッド記述子INVOKESTATIC
(名前と未加工の引数の型)によって一意に識別され、同じクラス内で同じ記述を持つ静的メソッドと非静的メソッドの両方を定義することはできませんでした。また、バイト コードを検証するために、Java コンパイラはターゲット メソッドが有効かどうかを確認する必要があります。static
備考: これは v6ak の回答と矛盾します。ただし、非静的メソッドのメソッド記述子は、 への参照を含むように変更されませんthis.getClass()
。したがって、Java ランタイムは、仮想INVOKESMART
命令のメソッド記述子から適切なメソッド バインディングを常に推測できます。JVMS §4.3.3 を参照してください。
理論は以上です。ただし、両方の呼び出しタイプで表現される意図はまったく異なります。また、Java バイトコードは、 javac以外のツールでもJVM アプリケーションを作成するために使用されることになっていることを思い出してください。これらのツールは、バイト コードを使用して、Java ソース コードよりもマシン コードに似たものを生成します。しかし、それはまだかなり高いレベルです。たとえば、バイト コードは引き続き検証され、バイト コードはマシン コードにコンパイルされるときに自動的に最適化されます。ただし、バイトコードは、意味を持たせるために意図的に冗長性を含む抽象化です。バイトコードのより明示的。また、Java 言語が言語を読みやすくするために類似のものに異なる名前を使用しているように、バイトコード命令セットにも冗長性が含まれています。また、別の利点として、メソッドの呼び出しタイプを常に推測する必要はなく、バイト コードで明示的に記述されているため、検証とバイト コードの解釈/コンパイルを高速化できます。検証、解釈、およびコンパイルは実行時に行われるため、これは望ましいことです。
最後の逸話として、Java 5 より前はクラスの静的イニシャライザーに<clinit>
フラグが立てられていなかったことに言及する必要がありstatic
ます。このコンテキストでは、メソッドの名前から静的呼び出しを推測することもできますが、これはさらに多くの実行時のオーバーヘッドを引き起こします。