Javaリロードメソッドで使用可能な修飾子について
一、finalのリロードパラメータの可用性
前にコードを書く時、一つのリロード方法でRunnable匿名クラスを使うため、パラメータをfinal指定する必要があり、ベースクラスのパラメータにはfinal修飾子がないため、ベースクラスの関数の原型は以下の通りである.
内部でfinal変数を再宣言して値を割り当てるつもりです.
しかし、試してみると、ベースクラスのメソッドのパラメータがfinalを宣言していなくても、リロードメソッドにfinalを直接追加できることが分かった.
コンパイルは通過できます.
二、具体的な原因
その後stackoverflowで関連する原因を探したところ、以下の解釈が見つかった.
According to the Java Language Specification 4.12.4:
Declaring a variable final can serve as useful documentation that its value will not change and can help avoid programming errors.
However, a
It can't be used to match signatures since it is does not appear in the actual .class file. It is for the compiler only.
具体的には、final修飾子は現在の実装関数でのみ機能するため、コンパイラへのヒントであり、具体的な.classファイルには現れず、パラメータがfinalであるかどうかにかかわらずjavaはpass by valueのパラメータ形式のみを行う.結局、finalは現在のリロード関数の具体的な実現を代表しているだけで、インタフェースとは関係ないので、JSE規範ではこれを関数署名に入れていないので、具体的な実現の詳細に属しています.
三、その他使用可能な修飾
ここで少し拡張します.同じ原理のsynchronizedキーワードもあります.
すなわち、リロード関数にsynchronizedキーワードを追加することは、finalの意味と同様に、インタフェース宣言に影響を与えない現在の関数の具体的な実装であるため、同様に許容される.
宣言の異常放出については、インタフェースの実装を招くため、異なるルールがあります.
具体例は以下の通りです.
上の例ではコンパイルに失敗しますが、具体的にはJSONExceptionを投げ出すため、ベースクラスよりもチェック済みの異常を多く投げ出すことになります.
興味深いことに、上記の例のコンパイルは、ベースクラスよりも少ない宣言でチェックされた異常ですが、通過できます.
しかし、このようにするのは確かに合理的で、インタフェースを実現する関数は必然的にインタフェースより多くの異常を持つことができなくて、さもなくばインタフェースの使用に影響します.
また,修飾子に対してインタフェースの権限を下回ってはならないなど,インタフェースがprotectedであり,実装関数はprotected以上の権限修飾でなければならない.
四、詳細
具体的には、JSEのリロード関数に関する要件を参照してください.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.3
関数署名の説明:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.2
前にコードを書く時、一つのリロード方法でRunnable匿名クラスを使うため、パラメータをfinal指定する必要があり、ベースクラスのパラメータにはfinal修飾子がないため、ベースクラスの関数の原型は以下の通りである.
public abstract void write(char[] buf, int offset, int count) throws IOException;
内部でfinal変数を再宣言して値を割り当てるつもりです.
@Override
public void write(char[] buf, int offset, int count) throws IOException {
final char[] writeBuf = buf;
}
しかし、試してみると、ベースクラスのメソッドのパラメータがfinalを宣言していなくても、リロードメソッドにfinalを直接追加できることが分かった.
@Override
public void write(final char[] buf, int offset, int count) throws IOException {
}
コンパイルは通過できます.
二、具体的な原因
その後stackoverflowで関連する原因を探したところ、以下の解釈が見つかった.
According to the Java Language Specification 4.12.4:
Declaring a variable final can serve as useful documentation that its value will not change and can help avoid programming errors.
However, a
final
modifier on a method parameter is not mentioned in the rules for matching signatures of overridden methods, and it has no effect on the caller, only within the body of an implementation. It can't be used to match signatures since it is does not appear in the actual .class file. It is for the compiler only.
具体的には、final修飾子は現在の実装関数でのみ機能するため、コンパイラへのヒントであり、具体的な.classファイルには現れず、パラメータがfinalであるかどうかにかかわらずjavaはpass by valueのパラメータ形式のみを行う.結局、finalは現在のリロード関数の具体的な実現を代表しているだけで、インタフェースとは関係ないので、JSE規範ではこれを関数署名に入れていないので、具体的な実現の詳細に属しています.
三、その他使用可能な修飾
ここで少し拡張します.同じ原理のsynchronizedキーワードもあります.
@Override
public synchronized void write(final char[] buf, int offset, int count) throws IOException {
}
すなわち、リロード関数にsynchronizedキーワードを追加することは、finalの意味と同様に、インタフェース宣言に影響を与えない現在の関数の具体的な実装であるため、同様に許容される.
宣言の異常放出については、インタフェースの実装を招くため、異なるルールがあります.
具体例は以下の通りです.
@Override
public synchronized void write(final char[] buf, int offset, int count) throws JSONException {
}
上の例ではコンパイルに失敗しますが、具体的にはJSONExceptionを投げ出すため、ベースクラスよりもチェック済みの異常を多く投げ出すことになります.
@Override
public synchronized void write(final char[] buf, int offset, int count) {
}
興味深いことに、上記の例のコンパイルは、ベースクラスよりも少ない宣言でチェックされた異常ですが、通過できます.
しかし、このようにするのは確かに合理的で、インタフェースを実現する関数は必然的にインタフェースより多くの異常を持つことができなくて、さもなくばインタフェースの使用に影響します.
また,修飾子に対してインタフェースの権限を下回ってはならないなど,インタフェースがprotectedであり,実装関数はprotected以上の権限修飾でなければならない.
四、詳細
具体的には、JSEのリロード関数に関する要件を参照してください.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.3
関数署名の説明:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.2