web-dev-qa-db-ja.com

Java最終抽象クラス

私は非常に簡単な質問があります:

私はJavaクラス、1つのパブリックな静的メソッドを提供し、何かをします。これは単にカプセル化の目的のためです(1つの別個のクラス内で重要なものすべてを持つため)...

このクラスは、インスタンス化も拡張も行わないでください。それは私に書いた:

final abstract class MyClass {
   static void myMethod() {
      ...
   }
   ... // More private methods and fields...
}

(私は知っていましたが、禁止されています)。

また、このクラスを最終的にのみ作成し、プライベートにしながら標準コンストラクタをオーバーライドできることも知っています。

しかし、これは「回避策」のように思え、最終的な抽象クラスによって行われる可能性が高いです...

そして、私は回避策が嫌いです。だから私自身の興味のために:別のより良い方法はありますか?

37
Sauer

参照:Effective Java 2nd Edition Item 4 "プライベートコンストラクターによるインスタンス化不可能性の強制"

public final class MyClass { //final not required but clearly states intention
    //private default constructor ==> can't be instantiated
    //side effect: class is final because it can't be subclassed:
    //super() can't be called from subclasses
    private MyClass() {
        throw new AssertionError()
    }

    //...
    public static void doSomething() {}
}
46
assylias

インスタンスなしでenumを使用するよりも簡単になりません。

public enum MyLib {;

   public static void myHelperMethod() { }
}

このクラスはfinalであり、インスタンスとプライベートコンストラクターは明示的にありません。

これは、ランタイムエラーとしてではなく、コンパイラによって検出されます。 (例外をスローするのとは異なり)

50
Peter Lawrey

いいえ、本体で例外をスローするプライベートな空のコンストラクターを作成する必要があります。 Javaはオブジェクト指向言語であり、インスタンス化されないクラスはそれ自体が回避策です!:)

final class MyLib{
    private MyLib(){
        throw new IllegalStateException( "Do not instantiate this class." );
    }

    // static methods go here

}
6
Tobogganski

いいえ、抽象クラスは拡張するためのものです。プライベートコンストラクターを使用してください。これは回避策ではありません-それを行う方法です!

4
scibuff

クラスのコンストラクターをprivateに宣言します。これにより、インスタンス化が不可能になり、サブクラス化が防止されます。

2

この場合の標準的な方法は、assylias(すべてJavaバージョン)およびPeter Lawrey(> = Java5))の提案です。

ただし、静的なユーティリティクラスの拡張を防ぐことは最終的な決定であり、後で別のプロジェクトに関連する機能があり、実際にあなたが気づいたときにあなたを悩ませる可能性があることに注意してくださいそれを拡張したい。

私は以下を提案します:

public abstract MyClass {

    protected MyClass() {
    }

    abstract void noInstancesPlease();

    void myMethod() {
         ...
    }
    ... // More private methods and fields...

}

これはagainst確立されたプラクティスです。必要に応じてクラスを拡張できるため、偶発的なインスタンス化を防ぐことができます(非常に明確なコンパイラエラーを発生させずに匿名サブクラスインスタンスを作成することもできません)。

JDKのユーティリティクラス(Java.util.Arraysなど)が実際に最終的に作成されたことは、常にpisses meです。比較を可能にするメソッドを持つArraysクラスを所有したい場合は、できません。別のクラスを作成する必要があります。これにより、(IMO)が一緒に属し、oneクラスを介して利用できる機能が配布されます。それにより、乱暴に分散されたユーティリティメソッドが残るか、メソッドのすべてを独自のクラスに複製する必要があります。

このようなユーティリティクラスを最終的にしないことをお勧めします。私の意見では、利点は欠点を上回っていません。

1
Durandal

クラスを抽象クラスと最終クラスの両方としてマークすることはできません。それらはほぼ反対の意味を持っています。抽象クラスはサブクラス化する必要がありますが、最終クラスはサブクラス化しないでください。クラスまたはメソッドの宣言に使用される抽象修飾子と最終修飾子のこの組み合わせを見ると、コードはコンパイルされません。

0