JavaでのMethod Sigunatureとは
JavaでのMethod Signatureとは
Java における Method Signature とは具体的に何を指すのでしょうか?
仕様差の確認
Java SE 18 Editionの2つの仕様を見比べてみます。
Java Language Specification(JLS)の 8.4.2 Method Signature によると、2つのメソッドの「メソッド名」と「引数の型」が同じであれば、これらのメソッドは同じとみなされます。
Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any), and, after adapting the formal parameter types of N to the type parameters of M, the same formal parameter types.
一方、Java Vitual Machine Specification(Java VM Spec.) の 4.7.9.1. Signatures では、「引数の型」、「復帰値」および「スローする例外」の3つの組み合わせで判別するとのことです。なんと、「メソッド名」が含まれていないのです。
A method signature for any method or constructor declaration which is either generic, or has a type variable or parameterized type as the return type or a formal parameter type, or has a type variable in a throws clause, or any combination thereof.
なぜ、こんな仕様差が出るのでしょうか?
そこで、バイトコードがどのような作りになっているかを紐解いてみましょう。
検証用のソースコード
まず、呼び出される側のクラスのJavaソース。 methodA
メソッドを持つクラスです。
class O {
static void methodA(String s) {
System.out.println(s);
}
}
次に呼び出す側です。これらのクラスの違いは、methodA
の登場回数です。前者は3回、後者は1回のみです。
class A {
static final String S = "methodA";
public static void main(String[] args){
O.methodA("methodA");
}
}
class B {
public static void main(String[] args){
O.methodA("a");
}
}
バイトコードの中身
A
、B
クラスのバイトコードを javap -verbose <className>.class
でアセンブルした結果を、抜粋します。
:
Constant pool:
:
#2 = String #18 // methodA
#3 = Methodref #19.#20 // O.methodA:(Ljava/lang/String;)V
:
#18 = Utf8 methodA
#19 = Class #23 // O
#20 = NameAndType #18:#24 // methodA:(Ljava/lang/String;)V
:
#23 = Utf8 O
#24 = Utf8 (Ljava/lang/String;)V
:
:
#3 = Methodref #16.#17 // O.methodA:(Ljava/lang/String;)V
:
#16 = Class #20 // O
#17 = NameAndType #21:#22 // methodA:(Ljava/lang/String;)V
:
#20 = Utf8 O
#21 = Utf8 methodA
#22 = Utf8 (Ljava/lang/String;)V
注目点が2つあります。
- 両クラスとも
methodA
文字列を1箇所のみで定義している - 呼び出し先の
NameAndType
の参照先が、次のように異なる- Aクラスでは、#18、#24と離れている
- Bクラスでは、#21、#22とくっついている
考察
バイトコードでは、 methodA
文字列の定義を1箇所のみに集約するのも、呼び出し先メソッド情報を「メソッド名」と「引数・復帰値」の2つに分けて定義するのも、Constant pool
資源を最小化するためにあることが伺えます。これによって、Javaアプリケーション実行時のJavaヒープの節約につながるわけです。
重複した文字列や「引数・復帰値」の定義を集約したバイトコード設計だと考えれば、Java VM Spec. の Method Signature がメソッド名を含めない合理性に合点できるのではないでしょうか?
追記
見直してみると、バイトコードにはメソッドの「引数・復帰値」の定義があるのですが、クラス名は集約していないですね。なので、以上の推察は当てにならないかと思い至っています。
#24 = Utf8 (Ljava/lang/String;)V
#22 = Utf8 (Ljava/lang/String;)V
Author And Source
この問題について(JavaでのMethod Sigunatureとは), 我々は、より多くの情報をここで見つけました https://zenn.dev/s2k3/articles/cce3a12473b1bd著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Collection and Share based on the CC protocol