web-dev-qa-db-ja.com

静的変数はなぜ悪と見なされるのですか?

私は、企業の世界では初めてのJavaプログラマーです。最近私は Groovy とJavaを使ってアプリケーションを開発しました。私が書いたコードを通して、かなりの数の統計を使用しました。私は上級テクニカルロットから、使用された統計の数を減らすように依頼されました。私は同じことについてグーグルしました、そして私は多くのプログラマーがスタティック変数を使用することにかなり反対しているのを見つけます。

私は静的変数を使うほうが便利だと思います。クラス内で関数を10,000回呼び出す必要がある場合は、メソッドを静的にして代わりに単純なClass.methodCall()を使用してもよいので嬉しいです。クラスの10,000個のインスタンスでメモリが散らかっているのではないでしょうか。

さらに、静的はコードの他の部分への相互依存性を減らします。彼らは完璧な国家保有者として行動することができます。これに加えて、私は、統計が SmalltalkScala のようないくつかの言語で広く実装されていることがわかりました。それでは、なぜこの静的な抑圧がプログラマーの間で広まっているのでしょうか(特にJavaの世界で)。

シモンズ:統計についての私の仮定が間違っているならば私を訂正してください。

579
Vamsi Emani

静的変数はグローバル状態を表します。これを考えるのは難しいし、テストするのも難しいです。オブジェクトの新しいインスタンスを作成する場合、テスト内でその新しい状態について考えることができます。静的変数を使用しているコードを使用する場合、それはあらゆる状態にある可能性があります - そして何かがそれを変更する可能性があります。

私はしばらくの間続けることができましたが、考えるべきより大きな概念は何かの範囲が狭ければ狭いほど、それが推論するのがより簡単であるということです。私たちは小さなことを考えるのは得意ですが、モジュール性がなければ100万回線システムの状態を推論するのは困難です。ちなみに、これは静的変数だけでなく、あらゆることに当てはまります。

645
Jon Skeet

オブジェクト指向ではありません。 静的な統計が「悪」と見なされる理由の1つは、 オブジェクト指向のパラダイム に反することです。特に、データがオブジェクトにカプセル化されている(拡張、情報の隠蔽など)という原則に違反しています。あなたがそれらを使って説明しているように、統計は本質的にスコープのような問題に対処することを避けるためにグローバル変数としてそれらを使うことです。ただし、グローバル変数は、手続き型または命令型プログラミングパラダイムの定義的な特性の1つであり、「優れた」オブジェクト指向コードの特性ではありません。これは手続き上のパラダイムが悪いと言うことではありませんが、私はあなたの上司があなたが「良いオブジェクト指向のコード」を書くことを期待していて、本当に「良い手続き型コード」を書きたいと思っているという印象を受けます。

Javaには、すぐには明らかではない統計を使い始めるときに多くの落書きがあります。たとえば、同じVM内でプログラムのコピーが2つ実行されている場合、それらは静的変数の値を断片化し、互いの状態を混乱させるでしょうか。あるいは、クラスを拡張するとどうなりますか?静的メンバーをオーバーライドできますか?非常に多くの統計があり、そのメモリを他の必要なインスタンスオブジェクトに再利用できないため、VMはメモリ不足になっていませんか。

オブジェクトの有効期間: さらに、統計の有効期間はプログラムのランタイム全体に一致します。つまり、クラスの使用が終わっても、これらすべての静的変数のメモリをガベージコレクションすることはできません。たとえば、代わりに、変数を非静的にし、main()関数でクラスのインスタンスを1つ作成し、その10,000回の呼び出しが完了したら、特定の関数を10,000回実行するようにクラスに依頼した場合そして、あなたが単一のインスタンスへのあなたの参照を削除すると、あなたのすべての静的変数はガベージコレクションされ再利用される可能性があります。

特定の再利用を防止します。 また、静的メソッドを使用してインタフェースを実装することはできないため、静的メソッドを使用すると特定のオブジェクト指向機能が使用できなくなる可能性があります。

その他のオプション: もし効率があなたの主な関心事であるなら、通常作成よりも速いという呼び出しの利点だけを考えるよりもスピードの問題を解決するための他のより良い方法があるかもしれません。一時的または揮発性モディファイアがどこでも必要であるかどうか考えてください。インライン化される機能を保持するために、メソッドは静的ではなく最終としてマークされることがあります。メソッドパラメータおよび他の変数は、それらの変数を変更できるものについての仮定に基づいて特定のコンパイラ最適化を可能にするために最終的にマークすることができます。インスタンスオブジェクトは、毎回新しいインスタンスを作成するのではなく、複数回再利用できます。一般にアプリのためにオンにされるべきであるコンパイラー最適化スイッチがあるかもしれません。おそらく、10,000回の実行をマルチスレッド化し、マルチプロセッサコアを利用できるように設計を設定する必要があります。移植性が問題にならないのであれば、ネイティブメソッドを使用すると、統計よりも速度が向上することがあります。

何らかの理由でオブジェクトの複数のコピーが不要な場合は、 シングルトンデザインパターン がスレッドセーフ(シングルトンが適切にコーディングされていると仮定)などの静的オブジェクトよりも優れています。オブジェクトの使用時にサブクラス化、コードのテストおよびリファクタリングを行うことでオブジェクトが適切に初期化されていることを保証します。インスタンス変数を使用するようにすべての静的変数コードをリファクタリングするよりも、インスタンスの重複を防ぐためのコード。以前はそうしなければならなかったのですが、面白くないので、もっとたくさんのクラスを編集しなければならなくなり、新しいバグが発生する危険性が高まりました。欠点があるように見えても。私にとって、もしあなたが何かの複数のコピーを必要とする道を進んで決めるならば、必要とされるやり直しはおそらく統計を可能な限りまれに使用する最も説得力のある理由の一つです。したがって、静的なものが相互依存関係を減らすというあなたの意見にも同意できないでしょう。直接アクセスできる静的なものがたくさんある場合は、「やり方を知っているオブジェクト」というよりは、より結合されたコードになるでしょう。 「何か」.

257
Jessica Brown

悪は主観的な用語です。

あなたは創造と破壊に関して統計を統制しません。彼らはプログラムのロードとアンロードを最大限に活用して暮らしています。

統計は1つのスペースにあるので、それらを使用したいすべてのスレッドは、管理しなければならないアクセス制御を通過する必要があります。これは、プログラムがより密接に結合されていることを意味し、この変更は(J Skeetが言っているように)想定し管理することがより困難です。これにより、変更の影響を切り分けるという問題が発生し、テストの管理方法に影響があります。

これらは私が彼らと持っている2つの主要な問題です。

90
Preet Sangha

いいえ。グローバルな国家はそれ自体悪ではありません。しかし、あなたがそれを正しく使ったかどうかを見るために your /コードを見なければなりません。初心者が世界的な国家を虐待することはかなり可能です。彼があらゆる言語機能を悪用するように。

世界の国家は絶対に必要です。私たちはグローバルな国家を避けることはできません。私たちは世界の国家についての推論を避けることはできません。 - アプリケーションのセマンティクスを理解したい場合.

そのためにグローバルステートを排除しようとする人々は、必然的にはるかに複雑なシステムになってしまいます - そして、グローバルステートは依然として存在し、多くの間接層の下で巧妙に/ばかげて偽装されています。そして、私たちはまだ、すべての間接を解いた後で、世界の状態について推論しなければなりません。

春の人々のように、寛大にグローバル状態をxmlで宣言し、どういうわけかそれが優れていると思う。

@Jon Skeet if I create a new instance of an objectでは、オブジェクト内の状態と、オブジェクトをホストしている環境の状態という2つの理由があります。

55
irreputable

静的変数には、主に2つの問題があります。

  • スレッドセーフ - 静的リソースは定義上スレッドセーフではありません
  • コードの単純性 - ある静的変数がいつインスタンス化されるのか、また別の静的変数の前にインスタンス化されるのかどうかわかりません
30
sternr

「static」キーワードを「final」キーワードなしで使用している場合、これはデザインを慎重に検討するための合図です。変更可能な静的ファイナルオブジェクトも同じくらい危険なので、「ファイナル」があってもフリーパスではありません。

私は私が「決勝戦」なしで「静的」を見る時間のおよそ85%を推定するでしょう、それは間違っています。多くの場合、これらの問題を隠したり隠したりするための奇妙な回避策があります。

静的ミュータブルを作成しないでください。特にコレクション。一般に、コレクションは、それを含むオブジェクトが初期化されるときに初期化されるべきであり、それらが含まれるオブジェクトがいつ忘れられるかについてリセットされるか忘れられるように設計されるべきです。

統計を使用することは非常に微妙なバグを生み出す可能性があり、それはエンジニアを維持する日々の苦痛の原因となります。私は知っています、なぜなら私はこれらのバグを作成し捜し出したからです。

あなたがより多くの詳細が欲しいならば、読んでください…

統計を使わないのはなぜ?

テストを書いたり実行したりするだけでなく、すぐには明らかにならない微妙なバグを含む、staticに関する多くの問題があります。

静的オブジェクトに依存するコードは簡単に単体テストすることができず、静的データは(通常は)簡単にモックすることができません。

静的を使用する場合、より高レベルのコンポーネントをテストするためにクラスの実装を交換することは不可能です。たとえば、データベースからロードしたCustomerオブジェクトを返す静的CustomerDAOを想像してください。今、私はいくつかのCustomerオブジェクトにアクセスする必要があるCustomerFilterクラスを持っています。 CustomerDAOが静的な場合は、最初にデータベースを初期化して有用な情報を入力することなく、CustomerFilterのテストを書くことはできません。

データベースの作成と初期化には長い時間がかかります。そして私の経験では、あなたのDB初期化フレームワークは時間とともに変化し、データが変形し、テストが失敗するかもしれないことを意味します。 IE、顧客1は以前VIPだったが、DB初期化フレームワークが変更され、顧客1はもはやVIPではなくなりましたが、テストは顧客1をロードするようにハードコードされています…

より良い方法は、CustomerDAOをインスタンス化し、それが構築されたときにそれをCustomerFilterに渡すことです。 (もっと良い方法はSpringや他のInversion of Controlフレームワークを使うことです。

これを実行したら、CustomerFilterTestの代替DAOをすばやく模擬するかスタブすることで、テストをより細かく制御できます。

静的DAOがないと、テストはより速くなり(データベース初期化なし)、より信頼性が高くなります(データベース初期化コードが変更されても失敗しないためです)。たとえば、この場合、テストに関する限り、顧客1がVIPであることを確認します。

テストの実行

一連の単体テストを(たとえば、Continuous Integrationサーバーと一緒に)実行すると、統計が本当の問題を引き起こします。あるテストから別のテストまで開いたままのネットワークSocketオブジェクトの静的マップを想像してください。最初のテストはポート8080でSocketを開くかもしれませんが、テストが中断されたときにMapをクリアするのを忘れていました。 2番目のテストが起動したとき、ポートがまだ占有されているため、ポート8080用に新しいSocketを作成しようとするとクラッシュする可能性があります。また、静的Collection内のSocket参照は削除されず、(WeakHashMapを除く)ガベージコレクションの対象にはならず、メモリリークが発生することもありません。

これは過度に一般化された例ですが、大規模システムでは、この問題はいつでも起こります。同じJVM内でソフトウェアの起動と停止を繰り返す単体テストは考えられませんが、これはソフトウェア設計の優れたテストであり、高可用性への願望がある場合は注意が必要です。

これらの問題は、フレームワークオブジェクト、たとえばDBアクセス、キャッシング、メッセージング、およびロギングレイヤでしばしば発生します。 Java EEやいくつかの最善のフレームワークを使用している場合、それらはおそらくあなたのためにこれの多くを管理しますが、私のようにあなたがレガシーシステムを扱っているなら.

これらのフレームワークコンポーネントに適用されるシステム構成が単体テスト間で変更され、単体テストフレームワークがコンポーネントを破棄して再構築しない場合、これらの変更は有効にならず、テストがそれらの変更に依存すると失敗します。 。

フレームワーク以外のコンポーネントでもこの問題の影響を受けます。 OpenOrdersという静的マップを想像してください。いくつかの未処理注文を作成するテストを1つ作成し、それらがすべて正しい状態にあることを確認した後、テストは終了します。別の開発者は、必要な注文をOpenOrdersマップに入れる2番目のテストを書いてから、注文の数が正確であると主張します。個別に実行すると、これらのテストは両方とも合格しますが、スイートで一緒に実行すると失敗します。

さらに悪いことに、失敗はテストが実行された順序に基づいているかもしれません。

この場合、統計を避けることで、テストインスタンス間でデータが保持されるリスクを回避し、テストの信頼性を向上させることができます。

微妙なバグ

高可用性環境で作業している場合、またはスレッドが開始および停止される可能性のある場所で作業をしている場合は、コードが本番環境で実行されているときにも単体テストスイートに関して前述したのと同じ懸念が当てはまります。

データを格納するために静的オブジェクトを使用するよりも、スレッドを扱うときは、スレッドの起動段階で初期化されたオブジェクトを使用することをお勧めします。このようにして、スレッドが開始されるたびに(潜在的に新しい構成で)オブジェクトの新しいインスタンスが作成され、スレッドのあるインスタンスから次のインスタンスへのデータの流出を防ぐことができます。

スレッドが停止しても、静的オブジェクトはリセットされず、ガベージコレクトもされません。 「EmailCustomers」というスレッドがあり、起動時に静的なStringコレクションに電子メールアドレスのリストが入力されてから、各アドレスへの電子メール送信が開始されるとします。スレッドが何らかの理由で中断またはキャンセルされたとしましょう。そのため、高可用性フレームワークはスレッドを再起動します。それからスレッドが起動するとき、それは顧客のリストをリロードします。しかし、このコレクションは静的なので、前のコレクションの電子メールアドレスのリストを保持することがあります。現在、一部の顧客は重複したEメールを受け取る可能性があります。

余談:スタティックファイナル

技術的な実装上の違いはありますが、「static final」の使用は事実上C #defineと同等のJavaです。 C/C++の#defineは、コンパイル前にプリプロセッサによってコードからスワップアウトされます。 Javaの「静的ファイナル」は、スタックに常駐するメモリーになります。このように、それは#defineよりもC++の“ static const”変数に似ています。

まとめ

これが、統計が問題を起こしているいくつかの基本的な理由の説明に役立つことを願っています。 Java EEやSpringなどの最新のJavaフレームワークを使用している場合、これらの状況の多くに遭遇することはないかもしれませんが、大量のレガシーコードを使用している場合、それらははるかに頻繁になります。

27
JBCP

*誰も言及していないので: 同時実行。 静的変数を読み書きする複数のスレッドがある場合、静的変数はあなたを驚かせることができます。これはウェブアプリケーション(例えば、ASP.NET)において一般的であり、それはいくつかのかなり厄介なバグを引き起こす可能性がある。たとえば、ページによって更新される静的変数があり、そのページが「ほぼ同時に」2人のユーザーによって要求されている場合、一方のユーザーが他方のユーザーによって予期される結果を得ることができます。

静的はコードの他の部分への相互依存を減らします。彼らは完璧な国家保有者として行動することができます

ロックを使用して競合に対処する準備ができているといいのですが。

*実際には、 Preet Sangha に言及されています。

14
Justin M. Keyes

クラス内の関数を10,000回呼び出す必要がある場合は、クラスの10,000個のインスタンスでメモリが雑然とするのではなく、メソッドを静的にして単純なclass.methodCall()を使用してください。

あるデータに対して関数の結果を単純に計算する必要性に対して、データを状態にカプセル化する必要性のバランスをとる必要があります。

さらに、静的はコードの他の部分への相互依存性を減らします。

カプセル化もそうです。大規模なアプリケーションでは、統計はスパゲッティコードを生成する傾向があり、リファクタリングやテストを簡単には許可しません。

他の回答もまた、統計の過剰使用に対して正当な理由を提供します。

13

静的変数はグローバルな状態を表しているため、一般的に悪いと見なされています。特に、それらはオブジェクト指向プログラミングの仮定を破ります。オブジェクト指向プログラミングでは、各オブジェクトはインスタンス(非静的)変数で表される独自の状態を持ちます。静的変数はインスタンス間の状態を表し、単体テストははるかに困難です。これは主に、静的変数への変更を単一のテストに限定することがより難しいためです。

そうは言っても、通常の静的変数(一般に悪いと考えられている)と最終の静的変数(AKA定数、それほど悪いことではない)とを区別することが重要です。

12
Jack Edmonds

Javaで静的メソッドを使用することの基本的な長所と短所をいくつか要約すると:

利点:

  1. グローバルにアクセス可能、つまり特定のオブジェクトインスタンスと結び付けられていない。
  2. JVMごとに1つのインスタンス。
  3. クラス名を使用してアクセスできます(オブジェクト不要)。
  4. すべてのインスタンスに適用可能な単一の値を含みます。
  5. JVMの起動時にロードされ、JVMのシャットダウン時に停止します。
  6. それらはObjectの状態を変更しません。

デメリット:

  1. 静的メンバーは、使用中であるかどうかにかかわらず、常にメモリーの一部です。
  2. あなたは静的変数の作成と破壊を制御することはできません。これらはプログラムのロード時に作成され、プログラムのアンロード時(またはJVMのシャットダウン時)に破棄されていると便利です。
  3. 同期を使用して静的スレッドを安全にすることができますが、追加の努力が必要です。
  4. あるスレッドが静的変数の値を変更すると、他のスレッドの機能を損なう可能性があります。
  5. 使用する前に「静的」を知っておく必要があります。
  6. 静的メソッドをオーバーライドすることはできません。
  7. シリアル化はそれらとうまく機能しません。
  8. それらはランタイムポリモーフィズムには参加しません。
  9. 多数の静的変数/メソッドが使用されている場合、メモリの問題が発生します(ある程度は考えられません)。プログラムが終了するまでそれらはガベージコレクトされないためです。
  10. 静的メソッドもテストが難しいです。
10
Virtual

私の意見では、パフォーマンスに関することはほとんどなく、デザインに関することです。静的変数の使用のように静的メソッドの使用が間違っているとは思いません(しかし、実際にはメソッド呼び出しについて話していると思います)。

それは単に論理を切り離してそれを良い場所にする方法に関するものです。 Java.lang.Mathが良い例である静的メソッドの使用を正当化することが時々あります。あなたがあなたのクラスの大部分をXxxUtilまたはXxxhelperと命名するとき、あなたはあなたのデザインを再考するほうがよいと思います。

9
M Platvoet

私はちょうど答えでなされたポイントのいくつかをまとめました。あなたが何か問題を見つけた場合は、それを修正してください。

スケーリング: JVMごとに静的変数のインスタンスが1つだけあります。図書館管理システムを開発していて、書籍には1つしかないため、書籍の名前に静的変数を付けることにしたとします。しかし、システムが成長し、複数のJVMを使用している場合は、どの書籍を扱っているのかを把握する方法がありません。

スレッドセーフ: /マルチスレッド環境で使用する場合は、インスタンス変数と静的変数の両方を制御する必要があります。しかし、インスタンス変数の場合、それがスレッド間で明示的に共有されていない限り保護を必要としませんが、静的変数の場合はプロセス内のすべてのスレッドによって常に共有されます。

テスト: テスト可能なデザインは良いデザインと同じではありませんが、テストできない良いデザインを観察することはめったにありません。静的変数はグローバルな状態を表すので、それらをテストすることは非常に難しくなります。

状態についての推論: クラスの新しいインスタンスを作成すると、このインスタンスの状態について推論できますが、静的変数がある場合は、どのような状態になってもかまいません。どうして?静的変数はインスタンス間で共有されるため、静的変数が別のインスタンスによって変更されている可能性があるためです。

シリアライゼーション: シリアライゼーションもそれらとうまく動作しません。

作成と破壊: 静的変数の作成と破壊は制御できません。通常、それらはプログラムのロード時およびアンロード時に作成および破棄されます。これは、それらがメモリ管理に悪く、また起動時に初期化時間を合計することを意味します。

しかし、本当にそれらが必要な場合はどうなりますか?

しかし時々、私たちは彼らの本当の必要性を持っているかもしれません。アプリケーション全体で共有される多くの静的変数の必要性を本当に感じているのであれば、1つの選択肢は、これらすべての変数を持つSingleton Designパターンを利用することです。あるいは、これらの静的変数を持ち、受け渡し可能なオブジェクトを作成することもできます。

また、静的変数がfinalとマークされている場合、それは定数になり、一度割り当てられた値は変更できません。それはそれが私たちがその可変性のために直面​​するすべての問題から私たちを救うことを意味します。

6
i_am_zero

静的変数を使うほとんどの場合、 シングルトンパターン を使いたいと思うかもしれません。

大域的状態の問題は、単純な文脈では大域的として意味があることがあり、実際的な文脈ではもう少し柔軟である必要があることです。そして、これがシングルトンパターンが役に立つところです。

6
Charles Goodwin

静的変数について質問しているようですが、あなたの例では静的メソッドも指摘しているようです。

静的変数は悪ではありません - ほとんどの場合、定数のようなグローバル変数としてfinal修飾子と組み合わせて採用されていますが、それを使い過ぎないようにします。

静的メソッド別名ユーティリティメソッド。一般的にはそれらを使用するのは悪い習慣ではありませんが、大きな懸念はそれらが 妨げになる可能性があるということです テスト。

たくさんの統計を使い正しいやり方でやる素晴らしいJavaプロジェクトの例として、 を見てください。フレームワーク 。その中でそれについての 議論 もあります。

静的インポートと組み合わせた静的変数/メソッドは、Javaで宣言型プログラミングを容易にするライブラリでも広く使用されています。 簡単にする または Hamcrest 。多くの静的変数とメソッドがなければ不可能です。

そのため、静的変数(およびメソッド)は優れていますが、それらを賢く使用してください。

6
cetnar

静的変数は最も重要なことにデータのセキュリティに問題を生じます(いつでも変更でき、誰でも変更でき、オブジェクトなしの直接アクセスなど)

詳細情報については これ ありがとう。

6
Anuj Patel

さらにもう1つの理由:脆弱性。

あなたがクラスを持っている場合、ほとんどの人はそれを作成して自由に使用できると期待しています。

あなたはそれが事実ではない、またはそれから保護することを文書化することができます(シングルトン/ファクトリーパターン) - しかしそれは余分な仕事であり、それ故に追加のコストです。それでも、大企業では、誰かがある時点であなたのクラスを使用しようと試みる可能性がありますが、すべてのNiceのコメントやファクトリに完全に注意を払う必要はありません。

静的変数を多用していると、それはうまくいきません。バグは高価です。

.0001%のパフォーマンス向上と潜在的に無知な開発者による変更に対する堅牢性の間では、多くの場合堅牢性が良い選択です。

5
ptyx

静的変数自体に問題はありません。壊れているのはJava構文だけです。各Javaクラスは、実際には2つの構造体(静的変数をカプセル化するシングルトンオブジェクト)とインスタンスを定義します。同じソースブロック内で両方を定義することは純粋に悪であり、読みにくいコードになります。 Scalaはそうしました。

4
Zdeněk Pavlas

「統計が悪である」という問題は、地球規模の国家に関する問題です。変数が静的になるための適切な時期は、変数が複数の状態を持つことがない場合です。フレームワーク全体からアクセス可能でなければならず、同じメソッド呼び出しに対して常に同じ結果を返すIEツールが静的と同じように「悪」ということは決してありません。あなたのコメントに関して:

私は静的変数を使うほうが便利だと思います。そして私もそれらが効率的であると思います

統計は変わらない変数/クラスに理想的で効率的な選択です

グローバル状態の問題はそれが作り出すことができる固有の不一致です。単体テストに関するドキュメンテーションはしばしばこの問題に対処します、無関係な複数のオブジェクトによってアクセスされることができるグローバル状態があるときはいつでもあなたの単体テストは不完全であり、「単体」粒度ではないでしょう。 グローバル状態とシングルトン についてのこの記事で述べたように、オブジェクトAとBが無関係の場合(一方が明示的に他方への参照を与えられていない場合)、AはBの状態に影響できないはずです。

時計など、良いコードでは禁止されているグローバル状態にはいくつかの例外があります。時間はグローバルであり、そしてある意味では、コード化された関係を持たずにオブジェクトの状態を変えます。

4
Bryan Agee

静的変数を使うほうが便利だと思う。クラス内で関数を10,000回呼び出す必要がある場合は、メソッドを静的にして、単純なclass.methodCall()を使用してください。クラスの10,000個のインスタンスでメモリが散らかっているのではなく、そうでしょうか。

私はあなたが思うことを見ます、しかし単純なシングルトンパターンは1万オブジェクトを例示する必要なしで同じことをするでしょう。

静的メソッドは、オブジェクトドメインに関連し、オブジェクトの内部プロパティを必要としない、または使用しない関数に対してのみ使用できます。

例:

public class WaterContainer {
    private int size;
    private int brand;
    ...etc

    public static int convertToGallon(int liters)...

    public static int convertToLiters(int gallon)...

}
4
Cygnusx1

私の0.02ドルは、これらの答えのいくつかが、「静的は悪い」と言っているのではなく、問題を混乱させているということです。私は、スコープとインスタンスについて話すほうが良いと思います。

私が言うことは、静的は「クラス」変数であるということです - それはそのクラスのすべてのインスタンスにわたって共有される値を表します。通常はそのようにスコープを設定する必要があります(クラスまたはそのインスタンスに対して保護されている、またはプライベートになっている)。

クラスレベルの振る舞いを取り囲んで他のコードに公開する予定の場合は、(@Jessicaが示唆しているように)シングルトンが将来の変更をサポートするためのより良い解決策になるかもしれません。これは、クラスレベルでは使用できない方法でインスタンス/シングルトンレベルでインターフェイスを使用できるためです。特に継承の場合です。

私が他の答えの側面のいくつかが質問の核心ではないと思う理由についてのいくつかの考え...

統計は「グローバル」ではありません。 Javaでは、スコープはstatic/instanceとは別に制御されます。

同時実行性は、インスタンスメソッドより静的にとって危険ではありません。それはまだ保護される必要があるという状態です。インスタンス変数がそれぞれ1つだけ、静的変数が1つだけのインスタンスが1000個あることは確かですが、どちらかにアクセスするコードがスレッドセーフな方法で記述されていない場合でも問題は解決しません。 。

ライフサイクルの管理は興味深い議論ですが、それほど重要ではないと思います。 init()/ clear()のような2つのクラスメソッドを管理することが、シングルトンインスタンスの作成と破棄よりも難しいのはなぜでしょうか。実際、GCのためにシングルトンはもう少し複雑であると言う人もいるかもしれません。

PS、Smalltalkに関して言えば、その方言の多くはクラス変数を持っていますが、Smalltalkではクラスは実際にはMetaclassのインスタンスなので、実際にはMetaclassインスタンス上の変数です。それでも、私は同じ経験則を適用します。それらがインスタンス間で共有状態に使用されている場合は問題ありません。それらがパブリック機能をサポートしているなら、あなたはシングルトンを見るべきです。ため息、私は確かにSmalltalkを見逃すことはありません....

4
studgeek

あなたの投稿には2つの主な質問があります。

まず、静的変数についてです。静的変数はまったく不要なので、使用は簡単に避けられます。 OOP言語全般、そして特にJavaでは、関数パラメータは参照によって渡されます。つまり、オブジェクトを関数に渡した場合、オブジェクトへのポインタを渡しているので、いけません。この情報を必要とする任意のスコープにオブジェクトへのポインタを渡すことができるので、静的変数を定義する必要があります。実際のメモリページングシステムはこれを処理するように最適化されているので、これによってパフォーマンスが低下することはありません。また、新しいページに渡されたポインタによって参照されるページはメモリ内に保持されます。範囲;静的変数を使用すると、アクセスが必要になったときにシステムがそれらが格納されているメモリページをロードする可能性があります(これは、ページが長期間アクセスされなかった場合に起こります)。良い習慣は、すべての静的なstufをいくつかの小さな「構成クラス」にまとめることです。これはシステムがそれをすべて同じメモリページに入れることを保証します。

次に、静的メソッドについてです。静的メソッドはそれほど悪くありませんが、すぐにパフォーマンスが低下する可能性があります。たとえば、クラスの2つのオブジェクトを比較し、どちらのオブジェクトが大きいかを示す値を返すメソッド(通常の比較メソッド)を考えると、このメソッドは静的でもそうでなくてもかまいません。同じメソッドの静的バージョンを解決する必要がある3つの参照(クラスごとに1つと各オブジェクトごとに1つ)に直面する2つの参照(オブジェクトごとに1つ)だけを解決する必要があるためです。しかし、私が言うように、これはそれほど悪くありません。Mathクラスを見れば、静的メソッドとして定義された多くの数学関数を見つけることができます。これらのメソッドのすべてを数字を定義するクラスに入れることよりもはるかに効率的です。これらのメソッドのほとんどはめったに使用されず、それらすべてを数字クラスに含めるとクラスが非常に複雑になり、大量のリソースが不要になるためです。

結論として:静的または非静的メソッドを扱うときは、静的変数の使用を避け、正しいパフォーマンスの均衡を見つけます。

シモンズ:私の英語ですみません。

3
jrodriguez

a)プログラムに関する理由.

Global.fooという静的変数がアクセスされる小規模から中規模のプログラムがある場合は、通常その呼び出しはどこからも行われません - パスもタイムラインもないため、変数がどのように配置されるか使用されている。だれがそれを実際の値に設定したのか、どうすればわかりますか?今修正した場合、どうすればわかりますか、どうすればよいですか。何が起こっているのかを知るために、すべてのアクセスを収集するために、ソース全体を調べました。

コードを書いたばかりなので、その使い方を知っていれば問題は見えませんが、外国のコードを理解しようとすれば理解できるでしょう。

b)本当に必要なのはあなただけ?

静的変数は、同じJVM内で同じ種類の複数のプログラムが異なる値で実行されるのを防ぐことがよくあります。あなたは、あなたのプログラムの複数のインスタンスが有用であるという用途を予見しないことが多いですが、それが進化する場合、またはそれが他のものにとって役立つ場合、彼らはあなたのプログラムの複数のインスタンスを開始したい状況を経験するかもしれません。

多くの人が長時間にわたって集中的に使用しない、多かれ少なかれ無用なコードだけが、静的変数に適しています。

3
user unknown

共有/キャッシュ データおよび すべてのアクセス可能なメモリ (つまり、1つのJVM内でコンテキストに分割してはいけません)を必要とする一連のスレッドがある場合は、すべて(できる:)に目的があります。選択

- >もちろん1つのインスタンスしか強制できませんが、なぜでしょうか。
このスレッドの中には、統計ではなくて悪のコメントがいくつかあります。

3
tomasb

上記のすべての答えは、なぜ統計が悪いのかを示しています。それらがである理由は、実際にはそうでないときに、あなたがオブジェクト指向のコードを書いているという誤った印象を与えるからです。それは単なる悪です。

2
blockhead

静的変数は良くも悪もありません。それらは特定のインスタンスではなくクラス全体を記述する属性を表します。特定のクラスのすべてのインスタンスに対してカウンタを用意する必要がある場合は、静的変数が値を保持するのに適した場所になります。

インスタンス関連の値を保持するために静的変数を使用しようとすると問題が発生します。

2
Andres

ここにはたくさんの良い答えがあります。

メモリ:クラスローダが(一般的にはVMが死ぬまで)存続している限り、静的変数は存続しますが、これはバルクオブジェクト/参照が静的として格納されている場合に限ります。

モジュール化:IOC、dependencyInjection、proxyなどの概念を検討してください。すべてが完全に密結合/静的な実装に反対しています。

その他の欠点:スレッドの安全性、テスト容易性

1
147.3k

私の立場からすると、static変数は読み取り専用 data または作成された変数慣例によりだけであるべきです。

たとえば、いくつかのプロジェクトのUIがあり、国、言語、ユーザーロールなどのリストがあります。そして、このデータを整理するためのクラスがあります。このリストがないとアプリは機能しないことを絶対に確信しています。そのため、app initで最初に行うことは、このリストの更新をチェックし、(必要に応じて)apiからこのリストを取得することです。そのため、このデータはアプリ内に「常に」存在することに同意します。実際にはデータのみが読み取られるので、その状態を気にする必要はありません。この場合を考えると、これらのデータのインスタンスをあまり多く持ちたくないのです。この場合、{{ static.

0
qiAlex

多数のユーザーがいるアプリケーションがあり、静的フォームを定義している場合は、すべてのユーザーが他のすべてのユーザーのフォームも変更します。

0
seinta

静的キーワードでグローバル変数を過度に使用すると、アプリケーションのある時点でメモリリークが発生することもあります。

0
Rahul Anand