Javaのstaticキーワードの手引き

Javaの静的キーワードのガイド

1. 前書き

この記事では、Java言語のstaticキーワードについて詳しく説明します。 キーワードstaticを変数、メソッド、ブロック、ネストされたクラスに適用する方法と、それがどのような違いをもたらすかを説明します。

2. staticキーワードの構造

Javaプログラミング言語では、the keyword static indicates that the particular member belongs to a type itself, rather than to an instance of that type

つまり、静的メンバーのインスタンスが1つだけ作成され、クラスのすべてのインスタンスで共有されます。

image

キーワードは、変数、メソッド、ブロック、ネストされたクラスに適用できます。

3. staticフィールド(またはクラス変数)

Javaでは、if a field is declared static, then exactly a single copy of that field is created and shared among all instances of that class。 クラスを何回初期化するかは関係ありません。それに属するstaticフィールドのコピーは常に1つだけです。 このstaticフィールドの値は、異なるクラスの同じオブジェクトのすべてのオブジェクトで共有されます。

メモリの観点から、static variables go in a particular pool in JVM memory called Metaspace(Java 8より前は、このプールはPermanent GenerationまたはPermGenと呼ばれていましたが、完全に削除され、Metaspaceに置き換えられました)。

3.1. staticフィールドの例

いくつかの属性(インスタンス変数).を持つCarクラスがあるとします。このCarブループリントから新しいオブジェクトが初期化されるたびに、新しいオブジェクトごとにこれらのインスタンス変数の個別のコピーがあります。

ただし、初期化され、初期化時にアクセスしてインクリメントできるようにすべてのインスタンスで共有されるCarオブジェクトの数のカウントを保持する変数を探しているとします。

そこで、static変数が登場します。

public class Car {
    private String name;
    private String engine;

    public static int numberOfCars;

    public Car(String name, String engine) {
        this.name = name;
        this.engine = engine;
        numberOfCars++;
    }

    // getters and setters
}

これで、初期化されるこのクラスのすべてのオブジェクトについて、numberOfCars変数の同じコピーがインクリメントされます。 したがって、この場合、次のアサーションが真になります。

@Test
public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() {
    new Car("Jaguar", "V8");
    new Car("Bugatti", "W16");

    assertEquals(2, Car.numberOfCars);
}

3.2. staticフィールドを使用する説得力のある理由

  • 変数の値がオブジェクトに依存しない場合

  • 値がすべてのオブジェクトで共有されることになっている場合

3.3. 覚えておくべきキーポイント

  • static変数はクラスに属しているため、クラス名を使用して直接アクセスでき、オブジェクト参照は必要ありません。

  • static変数は、クラスレベルでのみ宣言できます

  • staticフィールドには、オブジェクトの初期化なしでアクセスできます

  • オブジェクト参照(ford.numberOfCars_) , we should refrain from using it as in this case it becomes difficult to figure whether it’s an instance variable or a class variable; instead, we should always refer to _static_ variables using class name (for example, in this case, _Car.numberOfCarsなど)を使用してstaticフィールドにアクセスできますが

4. staticメソッド(またはクラスメソッド)

staticフィールドと同様に、staticメソッドもオブジェクトではなくクラスに属しているため、メソッドが存在するクラスのオブジェクトを作成せずに呼び出すことができます。 これらは、クラスのオブジェクトを作成せずに使用することを目的としています。

4.1. staticメソッドの例

staticメソッドは通常、インスタンスの作成に依存しない操作を実行するために使用されます。

そのクラスのすべてのインスタンスで共有されることになっているコードがある場合は、そのコードをstaticメソッドで記述します。

public static void setNumberOfCars(int numberOfCars) {
    Car.numberOfCars = numberOfCars;
}

staticメソッドは、ユーティリティクラスまたはヘルパークラスを作成するためにも広く使用されているため、これらのクラスの新しいオブジェクトを作成せずに取得できます。

JDKのCollectionsまたはMathユーティリティクラス、ApacheのStringUtils、またはSpringフレームワークのCollectionUtilsを見て、すべてのメソッドがstaticであることに注意してください。

4.2. staticメソッドを使用する説得力のある理由

  • オブジェクトに依存しない静的変数やその他の静的メソッドにアクセス/操作するため

  • staticメソッドは、ユーティリティクラスとヘルパークラスで広く使用されています

4.3. 覚えておくべきキーポイント

  • Javaのstaticメソッドは、コンパイル時に解決されます。 メソッドのオーバーライドはランタイムポリモーフィズムの一部であるため、so static methods can’t be overridden

  • 抽象メソッドは静的にすることはできません

  • staticメソッドはthisまたはsuperキーワードを使用できません

  • インスタンス、クラスメソッド、および変数の以下の組み合わせが有効です。

    1. インスタンスメソッドは、インスタンスメソッドとインスタンス変数の両方に直接アクセスできます。

    2. インスタンスメソッドは、static変数およびstaticメソッドに直接アクセスすることもできます

    3. staticメソッドはすべてのstatic変数および他のstaticメソッドにアクセスできます

    4. static methods cannot access instance variables and instance methods directly;そのためには、オブジェクト参照が必要です

5. staticブロック

staticブロックは、static変数を初期化するために使用されます。 static変数は宣言時に直接初期化できますが、複数行の処理を行う必要がある場合があります。

このような場合、staticブロックが役立ちます。

static変数が初期化中に追加のマルチステートメントロジックを必要とする場合は、staticブロックを使用できます。

5.1. staticブロックの例

いくつかの定義済みの値でリストオブジェクトを初期化するとします。

これは、staticブロックで簡単になります。

public class StaticBlockDemo {
    public static List ranks = new LinkedList<>();

    static {
        ranks.add("Lieutenant");
        ranks.add("Captain");
        ranks.add("Major");
    }

    static {
        ranks.add("Colonel");
        ranks.add("General");
    }
}

この例では、Listオブジェクトをすべての初期値と宣言で初期化することはできません。そのため、ここではstaticブロックを使用しました。

5.2. staticブロックを使用する説得力のある理由

  • static変数の初期化に、割り当て以外の追加ロジックが必要な場合

  • 静的変数の初期化にエラーが発生しやすく、例外処理が必要な場合

5.3. 覚えておくべきキーポイント

  • クラスは複数のstaticブロックを持つことができます

  • staticフィールドとstaticブロックは、クラスに存在するのと同じ順序で解決および実行されます。

6. staticクラス

Javaプログラミング言語を使用すると、クラス内にクラスを作成できます。 1つの場所でのみ使用される要素をグループ化する説得力のある方法を提供します。これにより、コードをより整理し読みやすくすることができます。

ネストされたクラスアーキテクチャは2つに分かれています。

  • staticとして宣言されたネストされたクラスはstatic nested classesと呼ばれますが、

  • static以外のネストされたクラスは、inner classesと呼ばれます

これら2つの主な違いは、内部クラスはそれを囲むクラスのすべてのメンバー(privateを含む)にアクセスできるのに対し、staticのネストされたクラスは外部クラスの静的メンバーにのみアクセスできることです。

実際、static nested classes behaved exactly like any other top-level class but enclosed in the only class which will access it, to provide better packaging convenience.

6.1. staticクラスの例

シングルトンオブジェクトを作成するために最も広く使用されているアプローチは、staticのネストされたクラスを使用することです。これは、同期を必要とせず、習得と実装が簡単です。

public class Singleton  {
    private Singleton() {}

    private static class SingletonHolder {
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

6.2. static内部クラスを使用する説得力のある理由

  • 1か所でのみ使用されるクラスをグループ化すると、カプセル化が増加します

  • コードは、使用する場所が1つだけになる場所に近づけられます。これにより読みやすさが向上し、コードのメンテナンス性が向上します

  • ネストされたクラスが、それを囲むクラスインスタンスメンバーへのアクセスを必要としない場合は、staticとして宣言することをお勧めします。これにより、外部クラスに結合されないため、外部クラスに結合されないため、より最適になります。ヒープまたはスタックメモリを必要としません

6.3. 覚えておくべきキーポイント

  • static nested classes do not have access to any instance members of the enclosing outer class;オブジェクトの参照を介してのみそれらにアクセスできます

  • 静的にネストされたクラスは、プライベートクラスを含む、囲んでいるクラスのすべての静的メンバーにアクセスできます。

  • Javaプログラミング仕様では、最上位クラスをstaticとして宣言することはできません。クラス内のクラス(ネストされたクラス)のみをstaticとして作成できます

7. 結論

この記事では、staticキーワードの動作を確認しました。 また、静的フィールド、静的メソッド、静的ブロック、および静的内部クラスを使用する理由と利点についても読みます。

いつものように、完全なコードover on GitHubを見つけることができます。