web-dev-qa-db-ja.com

Javaでstaticキーワードを使用しないのはいつですか?

メソッドシグネチャでJava)でstaticキーワードを使用するのは、いつ不適切と見なされますか?メソッドがいくつかの引数に基づいて関数を実行し、静的でないフィールドへのアクセスを必要としない場合は、これらのタイプのメソッドを常に静的にしたいのではないでしょうか。

29
user4903

may静的にしたくない理由の1つは、サブクラスでオーバーライドできるようにするためです。言い換えると、動作はオブジェクト内のデータではなく、オブジェクトの正確なタイプに依存する可能性があります。たとえば、isReadOnlyプロパティを持つ一般的なコレクションタイプがあり、常に可変のコレクションではfalseを返し、常に不変のコレクションではtrueを返します。他のインスタンス変数。

ただし、これは私の経験では非常にまれであり、明確にするために通常は明示的に指定する必要があります。通常は、オブジェクトの状態に依存しないメソッドを静的に作成します。

31
Jon Skeet

大規模なJavaアプリケーションでこれまでに遭遇する最大の悪の2つは

  • 純粋関数であるものを除く静的メソッド*
  • 可変静的フィールド

これらは、コードのモジュール性、拡張性、およびテスト容易性を、この限られた時間とスペースで納得させることはできないと私が理解する程度まで台無しにします。

*「純粋関数」とは、状態を変更せず、その結果が提供されたパラメーターのみに依存するメソッドのことです。したがって、たとえば、I/Oを(直接的または間接的に)実行する関数は純粋関数ではありませんが、Math.sqrt()はもちろん純粋関数です。

純粋関数についてもっと何とか (自己リンク)そしてなぜあなたがそれらに固執したいのか。

SpringやGuiceなどのフレームワークによってサポートされている可能性のある「依存性注入」スタイルのプログラミングを支持することを強くお勧めします(免責事項:私は後者の共著者です)。これを正しく行うと、本質的に決して可変の静的状態または非純粋な静的メソッドが必要になります。

47

一般的に、私は次の理由でインスタンスメソッドを好みます。

  1. 静的メソッドは、置き換えることができないため、テストが困難になります。
  2. 静的メソッドは、より手続き型です。

私の意見では、静的メソッドはユーティリティクラス(StringUtilsなど)には問題ありませんが、できるだけ使用しないようにしています。

23
Pascal Thivent

あなたの言うことは一種の真実ですが、派生クラスでそのメソッドの動作をオーバーライドしたい場合はどうなりますか?静的な場合は、それを行うことはできません。

例として、次のDAO型クラスについて考えてみます。

class CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
       // Some implementation, created a prepared statement, inserts the customer record.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
       // Implementation
    }
}

現在、これらのメソッドはいずれも「状態」を必要としません。必要なものはすべてパラメーターとして渡されます。したがって、それらは簡単に静的になる可能性があります。これで、別のデータベース(たとえば、Oracle)をサポートする必要があるという要件が発生します。

これらのメソッドは静的ではないため、新しいDAOクラスを作成するだけで済みます。

class OracleCustomerDAO : CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
        // Oracle specific implementation here.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
        // Oracle specific implementation here.
    }
}

この新しいクラスは、古いクラスの代わりに使用できるようになりました。依存性注入を使用している場合は、コードをまったく変更する必要がない場合もあります。

しかし、これらのメソッドを静的にした場合、新しいクラスの静的メソッドを単純にオーバーライドすることはできないため、事態はさらに複雑になります。

4
Eric Petroelje

静的メソッドは通常、2つの目的で記述されます。最初の目的は、 Java.util.Collections にあるような機能に似た、ある種のグローバルユーティリティメソッドを持つことです。これらの静的メソッドは一般的に無害です。 2番目の目的は、オブジェクトのインスタンス化を制御し、 シングルトンファクトリ などのさまざまなデザインパターンを介してリソース(データベース接続など)へのアクセスを制限することです。これらは、実装が不十分な場合、問題を引き起こす可能性があります。

私にとって、静的メソッドを使用することには2つの欠点があります。

  1. これらにより、コードのモジュール性が低下し、テスト/拡張が困難になります。ほとんどの回答はすでにこれに対処しているので、これ以上は説明しません。
  2. 静的メソッドは、何らかの形のグローバル状態をもたらす傾向があり、これはしばしば潜行性のバグの原因となります。これは、上記の2番目の目的で記述された不十分に記述されたコードで発生する可能性があります。詳しく説明させてください。

たとえば、特定のイベントをデータベースに記録する必要があり、他の状態についてもデータベース接続に依存しているプロジェクトについて考えてみます。通常、データベース接続が最初に初期化され、次にログフレームワークが特定のログイベントをデータベースに書き込むように構成されていると想定します。ここで、開発者が手書きのデータベースフレームワークからhibernateなどの既存のデータベースフレームワークに移行することを決定したと仮定します。

ただし、このフレームワークには独自のログ構成がある可能性があります。同じログフレームワークを使用している場合は、構成間でさまざまな競合が発生する可能性があります。突然、別のデータベースフレームワークに切り替えると、システムのさまざまな部分で、一見無関係に見えるエラーや障害が発生します。このような障害が発生する理由は、ロギング構成が静的メソッドおよび変数を介してアクセスされるグローバル状態を維持し、さまざまな構成プロパティがシステムのさまざまな部分によってオーバーライドされる可能性があるためです。

これらの問題を回避するために、開発者は静的メソッドと変数を介して状態を保存することを避ける必要があります。代わりに、ユーザーが必要に応じて状態を管理および分離できるようにするクリーンなAPIを構築する必要があります。 BerkeleyDB はここでの良い例であり、静的呼び出しではなく Environment オブジェクトを介して状態をカプセル化します。

1
toluju

そのとおり。実際、他の方法では合理的な設計(クラスに関連付けられていない一部の関数を持つため)をJava用語に歪める必要があります。そのため、FredsSwingUtilsやYetAnotherIOUtilsなどのキャッチオールクラスが表示されます。 。

0

そのクラスのオブジェクトとは独立してクラスメンバーを使用する場合は、静的として宣言する必要があります。
静的に宣言されている場合、クラスのオブジェクトの既存のインスタンスがなくてもアクセスできます。静的メンバーは、その特定のクラスのすべてのオブジェクトによって共有されます。

0
Gnark

ここで2つの質問1)オブジェクトを作成する静的メソッドは、最初にアクセスされたときにメモリにロードされたままになりますか?これ(メモリにロードされたまま)は欠点ではありませんか? 2)Javaを使用する利点の1つは、ガベージコレクション機能です。静的メソッドを使用するときにこれを無視しますか?

0
Subramanian

静的メソッドに関する追加の煩わしさ:そのような関数への参照を、その周りにラッパークラスを作成せずに渡す簡単な方法はありません。例えば。 - 何かのようなもの:

FunctorInterface f = new FunctorInterface() { public int calc( int x) { return MyClass.calc( x); } };

私はこの種のJava make-workが嫌いです。多分それ以降のバージョンのJavaはデリゲートまたは同様の関数ポインタ/手続き型メカニズムを取得しますか?

ちょっとした不満ですが、もう1つnotは、無償の静的関数、er、メソッドについてのようです。

0
Roboprog