370

次のような例を見てきました。

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

そして、定数をラップするための Constants クラスを用意して、それらを static final と宣言できると仮定しました。私は事実上 Java をまったく知らないので、これが定数を作成する最良の方法であるかどうか疑問に思っています。

4

28 に答える 28

402

それは完全に受け入れられ、おそらく標準でさえあります。

(public/private) static final TYPE NAME = VALUE;

ここTYPEで、 はタイプ、NAMEはスペースにアンダースコアを付けたすべて大文字の名前、VALUEは定数値です。

独自のクラスまたはインターフェイスに定数を配置しないことを強くお勧めします。

補足として: final と宣言され、可変である変数は引き続き変更できます。ただし、変数が別のオブジェクトを指すことはできません。

例えば:

public static final Point ORIGIN = new Point(0,0);

public static void main(String[] args){

    ORIGIN.x = 3;

}

これは正当でありORIGIN、(3, 0) のポイントになります。

于 2008-09-15T19:39:48.023 に答える
234

単一の定数クラスを持つことは強くお勧めしません。当時は良い考えに思えるかもしれませんが、開発者が定数を文書化することを拒否し、クラスが 500 を超える定数を含むように成長し、それらの定数が互いにまったく関連していない (アプリケーションのまったく異なる側面に関連している) 場合、これは通常、定数ファイルは完全に読み取り不能になります。その代わり:

  • Java 5+ にアクセスできる場合は、列挙型を使用して、アプリケーション領域の特定の定数を定義します。アプリケーション領域のすべての部分は、これらの定数の定数値ではなく、列挙型を参照する必要があります。クラスを宣言する方法と同様に、列挙型を宣言できます。列挙型は、Java 5+ のおそらく最も (そしてほぼ間違いなく唯一の) 便利な機能です。
  • 特定のクラスまたはそのサブクラスの 1 つに対してのみ有効な定数がある場合は、それらを保護またはパブリックとして宣言し、階層の最上位クラスに配置します。このようにして、サブクラスはこれらの定数値にアクセスできます (そして、他のクラスがパブリックを介してそれらにアクセスする場合、定数は特定のクラスに対してのみ有効ではありません...つまり、この定数を使用する外部クラスは、定数を含むクラス)
  • 動作が定義されたインターフェースを持っているが、戻り値または引数値が特定でなければならない場合、他の実装者がそれらにアクセスできるように、そのインターフェースで定数を定義することは完全に受け入れられます。ただし、定数を保持するためだけにインターフェイスを作成することは避けてください。定数を保持するためだけに作成されたクラスと同じくらい悪くなる可能性があります。
于 2008-09-15T19:51:44.597 に答える
120

定数を保持するためだけにインターフェイスを使用するのは悪い習慣です ( Josh Bloch によって定数インターフェイス パターンと名付けられました)。ジョシュは次のようにアドバイスしています。

定数が既存のクラスまたはインターフェイスに強く結び付けられている場合は、それらをクラスまたはインターフェイスに追加する必要があります。たとえば、Integer や Double などのボックス化されたすべての数値プリミティブ クラスは、MIN_VALUE および MAX_VALUE 定数をエクスポートします。定数が列挙型のメンバーとして最適に表示される場合は、それらを列挙 型でエクスポートする必要があります。それ以外の場合は、インスタンス化できないユーティリティ クラスを使用して定数をエクスポートする必要があります。

例:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

命名規則について:

慣例により、そのようなフィールドには大文字で構成され、単語がアンダースコアで区切られた名前が付けられます。これらのフィールドには、プリミティブ値または不変オブジェクトへの参照が含まれていることが重要です。

于 2008-09-15T19:58:22.223 に答える
36

効果的なJava(第2版)では、定数に静的intの代わりに列挙型を使用することをお勧めします。

ここにJavaの列挙型に関する優れた記事があります:http: //java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

その記事の終わりに提起された質問は次のとおりであることに注意してください。

では、いつ列挙型を使用する必要がありますか?

の答えで:

定数の固定セットが必要なときはいつでも

于 2008-09-15T20:00:12.267 に答える
21

インターフェイスの使用は避けてください。

public interface MyConstants {
    String CONSTANT_ONE = "foo";
}

public class NeddsConstant implements MyConstants {

}

魅力的ですが、カプセル化に違反し、クラス定義の区別が曖昧になります。

于 2008-09-15T19:45:33.800 に答える
18

私は次のアプローチを使用します。

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

たとえば、私はConstants.DB.Connection.URL定数を取得するために使用します。私にとっては、より「オブジェクト指向」に見えます。

于 2012-01-10T19:47:29.160 に答える
17

別のクラスで static final 定数を作成すると、問題が発生する可能性があります。Java コンパイラは実際にこれを最適化し、定数の実際の値をそれを参照する任意のクラスに配置します。

後で「定数」クラスを変更し、そのクラスを参照する他のクラスでハード再コンパイルを行わないと、古い値と新しい値の組み合わせが使用されることになります。

これらを定数と考えるのではなく、構成パラメーターと考えて、それらを管理するクラスを作成します。値を非最終的なものにし、ゲッターの使用を検討してください。将来、これらのパラメーターの一部を実際にユーザーまたは管理者が構成できるようにする必要があると判断した場合は、はるかに簡単に実行できるようになります。

于 2008-09-16T03:36:05.180 に答える
13

最も犯しやすい間違いは、Constants のような一般的な名前で呼び出されるグローバルにアクセス可能なクラスを作成することです。これは単にゴミが散らばり、システムのどの部分がこれらの定数を使用しているかを把握する能力をすべて失います。

代わりに、定数はそれらを「所有」するクラスに入る必要があります。TIMEOUT という定数はありますか? おそらく Communications() または Connection() クラスに入るはずです。MAX_BAD_LOGINS_PER_HOUR? User() に入ります。などなど。

他に考えられる用途は、実行時に「定数」を定義できるが、ユーザーが簡単に変更できない場合の Java .properties ファイルです。これらを .jar にパッケージ化して、Class resourceLoader で参照できます。

于 2008-09-15T20:26:15.183 に答える
6

それが正しい道です。

通常、定数は検出できないため、個別の「定数」クラスには保持されません。定数が現在のクラスに関連している場合、そこに保持しておくと次の開発者に役立ちます。

于 2008-09-15T19:44:16.487 に答える
5

私は、インターフェースを使用することが道ではないことに同意します。このパターンを回避することは、BlochのEffective Javaに独自のアイテム(#18)を持っています。

Blochが定数インターフェイスパターンに対して行う議論は、定数の使用は実装の詳細であるというものですが、定数を使用するためのインターフェイスを実装すると、エクスポートされたAPIでその実装の詳細が公開されます。

public|private static final TYPE NAME = VALUE;パターンは、定数を宣言するための良い方法です。個人的には、すべての定数を格納するために別のクラスを作成することは避けたほうがよいと思いますが、個人的な好みとスタイル以外に、これを行わない理由は見たことがありません。

定数を列挙型として適切にモデル化できる場合は、1.5以降で使用可能な列挙型構造を検討してください。

1.5より前のバージョンを使用している場合でも、通常のJavaクラスを使用してタイプセーフな列挙を実行できます。(詳細については、このサイトを参照してください)。

于 2008-09-15T20:00:43.543 に答える
5

列挙はどうですか?

于 2008-09-15T19:50:34.690 に答える
5

定数よりもゲッターを使用することを好みます。これらのゲッターは定数値を返すpublic int getMaxConnections() {return 10;}ことがありますが、定数を必要とするものはすべてゲッターを通過します。

利点の 1 つは、プログラムが定数を超えた場合 (構成可能にする必要があることがわかった場合)、getter が定数を返す方法を変更するだけでよいことです。

もう 1 つの利点は、定数を変更するために、それを使用するすべてのものを再コンパイルする必要がないことです。static final フィールドを参照すると、その定数の値はそれを参照する任意のバイトコードにコンパイルされます。

于 2008-09-16T01:30:29.540 に答える
4

上記のコメントに基づいて、これは昔ながらのグローバル定数クラス (public static final 変数を持つ) を、次のような方法で列挙型の同等のものに変更するための良いアプローチだと思います。

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

したがって、次のように参照できます。

Constants.StringConstant.DB_HOST
于 2011-06-26T21:16:48.933 に答える
3

優れたオブジェクト指向設計では、公開されている多くの定数は必要ありません。ほとんどの定数は、ジョブを実行するために必要なクラスにカプセル化する必要があります。

于 2008-09-15T23:58:26.797 に答える
2

これに答えるには、ある程度の意見があります。まず、Java の定数は一般に public、static、final として宣言されています。理由は次のとおりです。

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

インターフェイスは一般的に実装されることが期待されているため、CONSTANTS アクセサー/オブジェクトにインターフェイスを使用することは決してありません。これはおかしいと思いませんか:

String myConstant = IMyInterface.CONSTANTX;

代わりに、いくつかの小さなトレードオフに基づいて、いくつかの異なる方法から選択するので、必要なものによって異なります。

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe
于 2017-01-07T20:24:48.977 に答える
1

FWIW、秒単位のタイムアウト値は、おそらく構成設定(プロパティファイルから読み取られるか、Spring のように注入によって読み取られる)であり、定数ではないはずです。

于 2008-09-16T01:33:07.753 に答える
1

違いはなんですか

1.

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2.

public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

MyGlobalConstants.TIMEOUT_IN_SECSこの定数が必要な場所ならどこでも使用 できます。どちらも同じだと思います。

于 2010-12-09T21:11:54.430 に答える
1

final任意の型の定数は、クラス (修飾子を持つメンバー変数) 内の不変プロパティを作成することによって宣言できます。通常、修飾子staticpublic修飾子も提供されます。

public class OfficePrinter {
    public static final String STATE = "Ready";  
}

定数の値が選択肢の n タプル (列挙型など) からの選択を示すアプリケーションは数多くあります。この例では、割り当てられる可能性のある値を制限する列挙型を定義することを選択できます (つまり、型安全性が向上します)。

public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}
于 2008-09-15T21:17:31.130 に答える
1

単一の一般的な定数クラスはお勧めできません。定数は、それらが最も論理的に関連しているクラスと一緒にグループ化する必要があります。

あらゆる種類の変数 (特に列挙型) を使用するのではなく、メソッドを使用することをお勧めします。変数と同じ名前のメソッドを作成し、変数に割り当てた値を返すようにします。ここで、変数を削除し、その変数へのすべての参照を、作成したばかりのメソッドへの呼び出しに置き換えます。定数が十分に汎用的であり、それを使用するためだけにクラスのインスタンスを作成する必要がない場合は、定数メソッドをクラス メソッドにします。

于 2008-09-15T22:17:12.950 に答える
0

クラスを定数と同じ(大文字と小文字を除いて)とは呼びません...すべての定数が存在する「設定」、「値」、または「定数」の少なくとも1つのクラスがあります。それらが多数ある場合は、それらを論理定数クラス (UserSettings、AppSettings など) にグループ化します。

于 2008-09-15T19:41:23.963 に答える
0

定数の場合、 Enum の方が良い選択です。ここに例があります

パブリック クラス myClass {

public enum myEnum {
    Option1("String1", 2), 
    Option2("String2", 2) 
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}
于 2008-09-15T20:45:52.593 に答える
0

私がそれを行う方法の 1 つは、定数値を持つ「グローバル」クラスを作成し、定数へのアクセスが必要なクラスで静的インポートを行うことです。

于 2008-09-15T21:44:56.913 に答える
0

私はstatic final定数を宣言するために使用し、ALL_CAPS 命名表記を使用します。私は、すべての定数が 1 つのインターフェイスにまとめられている実際のインスタンスをかなり多く見てきました。いくつかの投稿では、これを悪い習慣と呼んでいますが、それは主に、それがインターフェイスの目的ではないためです。インターフェイスはコントラクトを強制する必要があり、無関係な定数を配置する場所であってはなりません。定数のセマンティクスが特定のクラスに属していない場合は、(プライベート コンストラクターを介して) インスタンス化できないクラスにそれをまとめても問題ありません( es)。私は常に、最も関連性の高いクラスに定数を配置します。これは理にかなっていて、保守も簡単だからです。

列挙型は、値の範囲を表すのに適していますが、絶対値 (例: TIMEOUT = 100 ミリ秒) に重点を置いてスタンドアロンの定数を格納している場合は、この方法を使用できますstatic final

于 2013-05-15T12:45:24.017 に答える
0

さらに一歩進めると、グローバルに使用される定数をインターフェイスに配置して、システム全体で使用できるようにすることができます。例えば

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

ただし、それを実装しないでください。完全修飾クラス名を介してコードで直接参照するだけです。

于 2008-09-15T19:45:34.407 に答える
0

static finalが私の好みenumです。アイテムが実際に列挙可能な場合にのみ使用します。

于 2012-08-31T01:49:03.907 に答える