[解決済み] Java 8のインターフェイスメソッドで "final "が使えないのはなぜですか?
質問
Java 8の最も便利な機能の1つは、新しく追加された
default
メソッドがあります。このメソッドが導入された理由は、基本的に2つあります(他にもあるかもしれません)。
-
実際のデフォルトの実装を提供する。例
Iterator.remove()
-
JDK APIの進化を可能にする。例
Iterable.forEach()
API設計者の立場からすると、インターフェイスメソッドに他の修飾子を使えるようにしてほしかった、例えば
final
. これは、便利なメソッドを追加するときに便利で、実装クラスでの偶発的なオーバーライドを防ぐことができます。
interface Sender {
// Convenience method to send an empty message
default final void send() {
send(null);
}
// Implementations should only implement this method
void send(String message);
}
上記は、すでに一般的な方法として
Sender
はクラスである。
abstract class Sender {
// Convenience method to send an empty message
final void send() {
send(null);
}
// Implementations should only implement this method
abstract void send(String message);
}
今すぐ
default
と
final
は明らかに矛盾するキーワードですが、デフォルトのキーワード自体は
は、厳密には必要なかったのでしょう。
という微妙な違いを反映させるために、この矛盾は意図的なものだと推測しています。
クラスメソッドとボディの組み合わせ。
(単なるメソッド)と
"ボディを持つインターフェースメソッド"
(デフォルトのメソッド) などの違いがあり、まだ理解できていません。
のようなモディファイアのサポートは、ある時点から開始されます。
static
と
final
をインターフェイスメソッドに適用することは、まだ十分に検討されていませんでした。
ブライアン・ゲッツの引用
:
もうひとつは、クラス構築をどこまでサポートするかということです。 インターフェイスのツール、例えばfinalメソッド、privateメソッド、protected メソッド、スタティックメソッドなど。 答えは、「まだわからない」です。
2011年末の当時から、明らかに
static
メソッドが追加されました。明らかに、これは JDK ライブラリ自体に多くの価値を付加するもので、例えば
Comparator.comparing()
.
質問です。
理由は何ですか?
final
(また
static final
は、Java 8 のインターフェースに採用されなかったのですか?
解決方法は?
この質問は、ある程度、次のことに関連しています。 Java 8のインターフェイスメソッドで "synchronized "が使えない理由は何ですか?
デフォルトのメソッドについて理解する上で重要なことは、設計の第一目標が インターフェイスの進化 インターフェイスを(平凡な)形質にしてしまうことではありません。 この2つの間には重複する部分があり、私たちは前者の邪魔にならないように後者に配慮しようとしましたが、この観点から見たとき、これらの質問は最もよく理解されるでしょう。 (なお、クラスメソッド は というのは、インターフェイスメソッドは多重継承が可能であるため、どのような意図があろうとも、インターフェイスメソッドとは異なるからです)。
デフォルトメソッドの基本的な考え方は、「デフォルトの実装を持つインターフェースメソッドであり、派生クラスはより具体的な実装を提供することができる」というものです。 そして、設計の中心はインターフェースの進化であったため、デフォルトメソッドをインターフェースに追加できるようにすることが重要な設計目標であった 事後 を、ソースとバイナリに互換性のある形で実現しました。
なぜファイナル・デフォルト・メソッドではないのか」に対する単純すぎる答えは、そうすればボディが単にデフォルトの実装になるのではなく、唯一の実装になるからです。 これは少し単純すぎる答えですが、この質問がすでに疑問の方向に向かっていることを示す手がかりになります。
Final Interfaceメソッドが疑問視されるもう一つの理由は、実装者に無理難題を突きつけるからです。 例えば、次のようなものがあったとします。
interface A {
default void foo() { ... }
}
interface B {
}
class C implements A, B {
}
ここでは、すべてがうまくいっています。
C
を継承しています。
foo()
から
A
. ここで、仮に
B
を持つように変更されました。
foo
メソッドで、デフォルトが設定されています。
interface B {
default void foo() { ... }
}
さて、再コンパイルするときは
C
に対してどのような振る舞いを継承すればいいのかわからないと、コンパイラは教えてくれます。
foo()
だから
C
はそれをオーバーライドしなければならない(そして、それを
A.super.foo()
同じ振る舞いを維持したい場合) しかし、もし
B
は、そのデフォルトの
final
を、そして
A
の作者の管理下にあるわけではありません。
C
? 現在
C
をオーバーライドしないとコンパイルできないのです。
foo()
をオーバーライドすることはできません。
foo()
でfinalだった場合
B
.
これはほんの一例ですが、ポイントは、メソッドのファイナリティは、単に振る舞いを提供し、多重継承が可能なインタフェースよりも、単一継承のクラス(一般に、振る舞いと状態を結びつける)の世界でより意味をなすツールである、ということです。 そして、インターフェイスのメソッドをfinalにすることは、このような問題を引き起こす可能性が高いのです。
もうひとつ、これらを認めない理由は、あなたが考えているような意味にはならないだろうからです。 デフォルトの実装は、クラス(またはそのスーパークラス)がメソッドの宣言(具象または抽象)を提供しない場合にのみ考慮されます。 もしデフォルトのメソッドが final であったとしても、スーパークラスがすでにそのメソッドを実装していれば、デフォルトは無視されるでしょう。 (このような継承の振る舞いは、デフォルトメソッドの設計の中心であるインターフェイスの進化を反映したものです。 すでに実装されているインターフェイスにデフォルトメソッド(または既存のインターフェイスメソッドに対するデフォルトの実装)を追加することが可能で、インターフェイスを実装する既存のクラスの振る舞いを変えることなく、デフォルトメソッドが追加される前にすでに機能していたクラスは、デフォルトメソッドが存在しても同じように動作することが保証されます)。
関連
-
java.util.NoSuchElementException 原因解析と解決方法
-
this()の呼び出しはコンストラクタ本体の最初の文でなければならない 例外解決と原因分析
-
サーブレットクラスのインスタンス化エラーの解決法
-
起動時にEclipseエラーが発生しました。起動中に内部エラーが発生しました。java.lang.NullPoin: "Javaツーリングの初期化 "中に内部エラーが発生しました。
-
Google Chromeのエラー「Not allowed to load local resource」の解決策について
-
[解決済み] なぜJavaにはtransientフィールドがあるのですか?
-
[解決済み] 特定のUnicode文字を含むコメントでのJavaコードの実行が許可されているのはなぜですか?
-
[解決済み] Java 8のmap()メソッドとflatMap()メソッドの違いは何ですか?
-
[解決済み] いつ使うか。Java 8+のインターフェイスのデフォルトメソッドと、抽象的なメソッドの比較
-
[解決済み】Java 8のインターフェースメソッドで "synchronized "が使えない理由は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
エラーの解決方法 jarfile XXX.jarにアクセスできません。
-
Spring BootのテストメソッドFailed to load ApplicationContextの問題を解決する
-
マスキング このリソースにアクセスするには、完全な認証が必要です。
-
org.glassfish.jersey.servlet.ServletContainer
-
java 例外。Javaツールの初期化
-
maven プラグイン エラー プラグインの実行は、ライフサイクル構成ソリューションの対象外です。
-
[解決済み] 特定のUnicode文字を含むコメントでのJavaコードの実行が許可されているのはなぜですか?
-
[解決済み] Javaインターフェースでスタティックメソッドを定義できないのはなぜですか?
-
[解決済み] なぜJavaは符号なしintをサポートしないのですか?
-
[解決済み】Java 8のインターフェースメソッドで "synchronized "が使えない理由は?