Java8:java.lang.Object のメソッドのデフォルト メソッドを定義することが禁止されているのはなぜですか

StackOverflow https://stackoverflow.com//questions/24016962

質問

デフォルト メソッドは、Java ツールボックスの優れた新しいツールです。ただし、を定義するインターフェイスを作成しようとしました default のバージョン toString 方法。Java は、メソッドが で宣言されているため、これは禁止されていると言います。 java.lang.Object じゃないかもしれない default編なぜそうなるのでしょうか?

「基本クラスが常に勝つ」というルールがあることはわかっているので、デフォルトでは (駄洒落 ;)、任意の default の実装 Object メソッドはからのメソッドによって上書きされます Object ともかく。ただし、からのメソッドに例外を設けるべきではない理由はわかりません。 Object 仕様では。特に toString デフォルトの実装があると非常に便利かもしれません。

では、Java 設計者が許可しないことに決めた理由は何でしょうか。 default メソッドのオーバーライド Object?

役に立ちましたか?

解決

これも言語設計の問題の 1 つであり、詳しく調べ始めると、実際には悪いアイデアであることがわかるまで、「明らかに良いアイデア」のように見えます。

このメール には、このテーマに関する多くの内容が含まれています (他のテーマについても同様です)。現在のデザインに至るまでには、いくつかのデザイン要素が集まりました。

  • 継承モデルをシンプルに保ちたいという要望。
  • 明白な例(例:方向転換など)を一度見れば、 AbstractList インターフェイスに))、equals/hashCode/toString の継承は単一の継承と状態に強く結びついており、インターフェイスは多重継承されステートレスであることがわかります。
  • それは潜在的にいくつかの驚くべき行動への扉を開く可能性があるということ。

「シンプルにする」という目標についてはすでに触れました。継承と競合解決のルールは非常にシンプルになるように設計されています (クラスはインターフェイスに優先し、派生インターフェイスはスーパーインターフェイスに優先し、その他の競合は実装クラスによって解決されます)。 もちろん、これらのルールを調整して例外を作成することもできますが、この糸を引っ張り始めると、徐々に複雑さが増していくのが、思っているほど小さくないことがわかると思います。

もちろん、複雑化を正当化するある程度の利点はありますが、この場合はそれがありません。ここで説明するメソッドは、equals、hashCode、および toString です。これらのメソッドはすべて本質的にオブジェクトの状態に関するものであり、そのクラスにとって等価性が何を意味するかを決定するのに最適な立場にあるのは、インターフェイスではなく状態を所有するクラスです (特に等価性の契約が非常に強力であるため)。驚くべき結果については、「効果的な Java」を参照してください)。インターフェイスライターはあまりにもかけ離れています。

引き出すのは簡単ですが、 AbstractList 例;取り除くことができれば素晴らしいでしょう AbstractList そしてその行動を List インターフェース。しかし、この明白な例を越えると、他に良い例はあまり見つかりません。根本的には、 AbstractList 単一継承用に設計されています。ただし、インターフェイスは多重継承用に設計する必要があります。

さらに、次のクラスを作成していると想像してください。

class Foo implements com.libraryA.Bar, com.libraryB.Moo { 
    // Implementation of Foo, that does NOT override equals
}

Foo 作者はスーパータイプを調べましたが、equals の実装は見当たらず、参照の等価性を得るには、から equals を継承するだけでよいと結論付けました。 Object. 。そして来週、Bar のライブラリ管理者が「協力して」デフォルトの equals 実装。おっと!さて、のセマンティクスは Foo 別のメンテナンス ドメインのインターフェイスによって、共通のメソッドのデフォルトが「役立つ」ように追加されているために壊れています。

デフォルトはデフォルトであるべきです。何も存在しなかったインターフェース (階層内のどこにも) にデフォルトを追加しても、具体的な実装クラスのセマンティクスには影響を与えません。しかし、デフォルトが Object メソッドを「オーバーライド」できるかというと、そうではありません。

したがって、これは無害な機能のように見えますが、実際には非常に有害です。表現力を少しずつ増分するだけで非常に複雑さが増し、個別にコンパイルされたインターフェイスに対する善意の無害に見える変更が、実装クラスの意図したセマンティクスを損なうことが非常に簡単になります。

他のヒント

It is forbidden to define default methods in interfaces for methods in java.lang.Object, since the default methods would never be "reachable".

Default interface methods can be overwritten in classes implementing the interface and the class implementation of the method has a higher precedence than the interface implementation, even if the method is implemented in a superclass. Since all classes inherit from java.lang.Object, the methods in java.lang.Object would have precedence over the default method in the interface and be invoked instead.

Brian Goetz from Oracle provides a few more details on the design decision in this mailing list post.

I do not see into the head of Java language authors, so we may only guess. But I see many reasons and agree with them absolutely in this issue.

The main reason for introducing default methods is to be able to add new methods to interfaces without breaking the backward compatibility of older implementations. The default methods may also be used to provide "convenience" methods without the necessity to define them in each of the implementing classes.

None of these applies to toString and other methods of Object. Simply put, default methods were designed to provide the default behavior where there is no other definition. Not to provide implementations that will "compete" with other existing implementations.

The "base class always wins" rule has its solid reasons, too. It is supposed that classes define real implementations, while interfaces define default implementations, which are somewhat weaker.

Also, introducing ANY exceptions to general rules cause unnecessary complexity and raise other questions. Object is (more or less) a class as any other, so why should it have different behaviour?

All and all, the solution you propose would probably bring more cons than pros.

The reasoning is very simple, it is because Object is the base class for all the Java classes. So even if we have Object's method defined as default method in some interface, it will be useless because Object's method will always be used. That is why to avoid confusion, we cannot have default methods that are overriding Object class methods.

To give a very pedantic answer, it is only forbidden to define a default method for a public method from java.lang.Object. There are 11 methods to consider, which can be categorized in three ways to answer this question.

  1. Six of the Object methods cannot have default methods because they are final and cannot be overridden at all: getClass(), notify(), notifyAll(), wait(), wait(long), and wait(long, int).
  2. Three of the Object methods cannot have default methods for the reasons given above by Brian Goetz: equals(Object), hashCode(), and toString().
  3. Two of the Object methods can have default methods, though the value of such defaults is questionable at best: clone() and finalize().

    public class Main {
        public static void main(String... args) {
            new FOO().clone();
            new FOO().finalize();
        }
    
        interface ClonerFinalizer {
            default Object clone() {System.out.println("default clone"); return this;}
            default void finalize() {System.out.println("default finalize");}
        }
    
        static class FOO implements ClonerFinalizer {
            @Override
            public Object clone() {
                return ClonerFinalizer.super.clone();
            }
            @Override
            public void finalize() {
                ClonerFinalizer.super.finalize();
            }
        }
    }
    
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top