web-dev-qa-db-ja.com

Java 8クラスにextension / defaultメソッドを追加

Javaを探しています。現在、Java 8のデフォルトメソッドについて読んでいますが、 、これらはインターフェイスにのみ追加できます...

...インターフェイスを実装しない最終クラスの拡張メソッドを記述できる言語機能はありますか? (ラップする必要はありません...)

34
Cheetah

C#拡張メソッドは、拡張型を最初の引数として使用する静的メソッドの単なる構文上の砂糖です。 Javaデフォルトのメソッドはまったく異なるものです。C#拡張メソッドを模倣するには、通常の静的メソッドを記述するだけです。ただし、シンタックスシュガーはありません; Javaはこの機能はありません。

Javaのデフォルトメソッドは、実際の仮想メソッドです。たとえば、オーバーライドできます。デフォルトのfoo()メソッドを宣言するインターフェースXから継承するクラスIを考えてください。 Xまたはそのスーパークラスのいずれかが独自のfoo()メソッドを宣言しない場合、XIfoo()実装を取得します。現在、YのサブクラスXは、通常のメソッドのようにX.foo()をオーバーライドできます。したがって、デフォルトのメソッドは構文上の砂糖だけではありません。これらはメソッドのオーバーライドと継承メカニズムの実際の拡張であり、他の言語機能では模倣できません。

デフォルトメソッドは特別なVMサポートを必要とするため、コンパイラのみの機能ではありません。クラスのロード中、クラスの階層をチェックして、継承するデフォルトメソッドを決定する必要があります。 、この決定はコンパイル時ではなく実行時に行われます。それについてのクールなことは、継承するインターフェイスが新しいデフォルトメソッドを取得するときにクラスを再コンパイルする必要がないことです:VMクラスのロード時に、新しいメソッドをそれに割り当てます。

23
gexicide

Javaには拡張メソッドがありません。デフォルトのメソッドは拡張メソッドではありません。各機能を見てみましょう。

Javaのデフォルトメソッド

解決された問題:

  1. 多くのオブジェクトは同じインターフェースを実装でき、それらはすべてメソッドに同じ実装を使用できます。基本クラスはこの問題を解決できますが、Javaは多重継承をサポートしないため、インターフェース実装者が基本クラスをまだ持っていない場合のみです。
  2. APIは、APIコンシューマーを壊すことなく、メソッドをインターフェイスに追加したいと考えています。これを解決するには、デフォルトの実装でメソッドを追加します。

Javaのデフォルトメソッドは、デフォルトの実装をインターフェイスに追加する機能です。そのため、インターフェイスを拡張するオブジェクトはメソッドを実装する必要がなく、デフォルトのメソッドを使用するだけで済みます。

interface IA { default public int AddOne(int i) { return i + 1; } }

IAを実装するオブジェクトは、使用される既定のメソッドがあるため、AddOneを実装する必要はありません。

public class MyClass implements IA { /* No AddOne implementation needed */ } 

C#にはこの機能がなく、この機能を追加することで大幅に改善されます。 (更新:C#8の機能)

C#の拡張メソッド

解決された問題:

  1. シールされたクラスにメソッドを追加する機能。
  2. 継承を強制せずに、サードパーティのライブラリからクラスにメソッドを追加する機能。
  3. モデルクラスのメソッドが慣習上の理由で許可されていない環境で、モデルクラスにメソッドを追加する機能。
  4. インテリセンスがこれらの方法をあなたに提示する能力。

例:型文字列はC#のシールドクラスです。文字列はシールされているため、継承できません。ただし、文字列から呼び出すことができるメソッドを追加できます。

var a = "mystring";
a.MyExtensionMethed()

Javaにはこの機能がなく、この機能を追加することで大幅に改善されます。

結論

JavaのデフォルトメソッドとC#の拡張メソッド機能については、類似したものはありません。それらは完全に異なり、完全に異なる問題を解決します。

23
Rhyous

C#拡張メソッドはstaticおよびse-siteですが、Javaのデフォルトメソッドはvirtualおよびdeclaration-siteです。

私があなたが望んでいると思うことは、あなたが制御していないクラスにメソッドを「モンキーパッチ」する機能ですが、Javaはあなたにそれを与えません(設計により;拒否されました。)

C#アプローチに対するデフォルトメソッドのもう1つの利点は、それらが反射的に発見可能であり、実際、外部からは「通常の」インターフェイスメソッドと何も変わらないように見えることです。

Javaのデフォルトメソッドに対するC#の拡張メソッドの利点の1つは、C#の具象ジェネリックを使用すると、拡張メソッドがclassesではなくtypesに注入されるため、sum()メソッドを_List<int>_に挿入します。

とりわけ、JavaのデフォルトメソッドとC#の拡張メソッドの主な哲学的な違いは、C#ではメソッドを型にインジェクトでき​​ることです制御しません(開発者にとっては確実に便利です)一方で、Javaの拡張メソッドはそれらが現れるAPIの第一級の部分(それらはインターフェースで宣言されている、反射的に発見可能など)これはいくつかの設計原則を反映しています。ライブラリ開発者はAPIの制御を維持でき、ライブラリの使用は透過的である必要があります。タイプYでメソッドx()を呼び出すことは、どこでも同じことを意味する必要があります。

21
Brian Goetz

拡張メソッドにいくつかのトリックを含めることは可能です。

LombokまたはXTendを試すことができます。拡張メソッドには、すぐに使用できるJava実装はありませんが、LombokとXTendの両方が完全に機能するソリューションを提供します。

Lombokはシンプルなスタンドアロンコード処理フレームワークであり、拡張メソッドを含む、批判されているJava固有の面倒な作業のほとんどを軽減します。 https://projectlombok.org/features/experimental/ExtensionMethod.html

Xtend http://www.Eclipse.org/xtend/ は数光年先に進み、Scalaなどの現代言語の最良の部分を組み合わせた言語を実装しますJavaおよびJava型システムの上。これにより、一部のクラスをXtendに実装し、他のクラスを同じプロジェクト内のJavaに実装できます。 Xtendコードは有効なJavaコードに準拠しているため、JVMマジックは内部で発生しません。一方、不足している拡張メソッドのみがある場合は少し多すぎます。

JPropel https://github.com/nicholas22/jpropel-light は、Lombokを使用してJavaでLINQスタイルの拡張メソッドを実装します。それは一見の価値があるかもしれません:)

7
Gee Bee