メソッドシグネチャでJava)でstaticキーワードを使用するのは、いつ不適切と見なされますか?メソッドがいくつかの引数に基づいて関数を実行し、静的でないフィールドへのアクセスを必要としない場合は、これらのタイプのメソッドを常に静的にしたいのではないでしょうか。
may静的にしたくない理由の1つは、サブクラスでオーバーライドできるようにするためです。言い換えると、動作はオブジェクト内のデータではなく、オブジェクトの正確なタイプに依存する可能性があります。たとえば、isReadOnly
プロパティを持つ一般的なコレクションタイプがあり、常に可変のコレクションではfalse
を返し、常に不変のコレクションではtrue
を返します。他のインスタンス変数。
ただし、これは私の経験では非常にまれであり、明確にするために通常は明示的に指定する必要があります。通常は、オブジェクトの状態に依存しないメソッドを静的に作成します。
大規模なJavaアプリケーションでこれまでに遭遇する最大の悪の2つは
これらは、コードのモジュール性、拡張性、およびテスト容易性を、この限られた時間とスペースで納得させることはできないと私が理解する程度まで台無しにします。
*「純粋関数」とは、状態を変更せず、その結果が提供されたパラメーターのみに依存するメソッドのことです。したがって、たとえば、I/Oを(直接的または間接的に)実行する関数は純粋関数ではありませんが、Math.sqrt()はもちろん純粋関数です。
純粋関数についてもっと何とか (自己リンク)そしてなぜあなたがそれらに固執したいのか。
SpringやGuiceなどのフレームワークによってサポートされている可能性のある「依存性注入」スタイルのプログラミングを支持することを強くお勧めします(免責事項:私は後者の共著者です)。これを正しく行うと、本質的に決して可変の静的状態または非純粋な静的メソッドが必要になります。
一般的に、私は次の理由でインスタンスメソッドを好みます。
私の意見では、静的メソッドはユーティリティクラス(StringUtils
など)には問題ありませんが、できるだけ使用しないようにしています。
あなたの言うことは一種の真実ですが、派生クラスでそのメソッドの動作をオーバーライドしたい場合はどうなりますか?静的な場合は、それを行うことはできません。
例として、次の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.
}
}
この新しいクラスは、古いクラスの代わりに使用できるようになりました。依存性注入を使用している場合は、コードをまったく変更する必要がない場合もあります。
しかし、これらのメソッドを静的にした場合、新しいクラスの静的メソッドを単純にオーバーライドすることはできないため、事態はさらに複雑になります。
静的メソッドは通常、2つの目的で記述されます。最初の目的は、 Java.util.Collections にあるような機能に似た、ある種のグローバルユーティリティメソッドを持つことです。これらの静的メソッドは一般的に無害です。 2番目の目的は、オブジェクトのインスタンス化を制御し、 シングルトン や ファクトリ などのさまざまなデザインパターンを介してリソース(データベース接続など)へのアクセスを制限することです。これらは、実装が不十分な場合、問題を引き起こす可能性があります。
私にとって、静的メソッドを使用することには2つの欠点があります。
たとえば、特定のイベントをデータベースに記録する必要があり、他の状態についてもデータベース接続に依存しているプロジェクトについて考えてみます。通常、データベース接続が最初に初期化され、次にログフレームワークが特定のログイベントをデータベースに書き込むように構成されていると想定します。ここで、開発者が手書きのデータベースフレームワークからhibernateなどの既存のデータベースフレームワークに移行することを決定したと仮定します。
ただし、このフレームワークには独自のログ構成がある可能性があります。同じログフレームワークを使用している場合は、構成間でさまざまな競合が発生する可能性があります。突然、別のデータベースフレームワークに切り替えると、システムのさまざまな部分で、一見無関係に見えるエラーや障害が発生します。このような障害が発生する理由は、ロギング構成が静的メソッドおよび変数を介してアクセスされるグローバル状態を維持し、さまざまな構成プロパティがシステムのさまざまな部分によってオーバーライドされる可能性があるためです。
これらの問題を回避するために、開発者は静的メソッドと変数を介して状態を保存することを避ける必要があります。代わりに、ユーザーが必要に応じて状態を管理および分離できるようにするクリーンなAPIを構築する必要があります。 BerkeleyDB はここでの良い例であり、静的呼び出しではなく Environment オブジェクトを介して状態をカプセル化します。
そのとおり。実際、他の方法では合理的な設計(クラスに関連付けられていない一部の関数を持つため)をJava用語に歪める必要があります。そのため、FredsSwingUtilsやYetAnotherIOUtilsなどのキャッチオールクラスが表示されます。 。
そのクラスのオブジェクトとは独立してクラスメンバーを使用する場合は、静的として宣言する必要があります。
静的に宣言されている場合、クラスのオブジェクトの既存のインスタンスがなくてもアクセスできます。静的メンバーは、その特定のクラスのすべてのオブジェクトによって共有されます。
ここで2つの質問1)オブジェクトを作成する静的メソッドは、最初にアクセスされたときにメモリにロードされたままになりますか?これ(メモリにロードされたまま)は欠点ではありませんか? 2)Javaを使用する利点の1つは、ガベージコレクション機能です。静的メソッドを使用するときにこれを無視しますか?
静的メソッドに関する追加の煩わしさ:そのような関数への参照を、その周りにラッパークラスを作成せずに渡す簡単な方法はありません。例えば。 - 何かのようなもの:
FunctorInterface f = new FunctorInterface() { public int calc( int x) { return MyClass.calc( x); } };
私はこの種のJava make-workが嫌いです。多分それ以降のバージョンのJavaはデリゲートまたは同様の関数ポインタ/手続き型メカニズムを取得しますか?
ちょっとした不満ですが、もう1つnotは、無償の静的関数、er、メソッドについてのようです。