JavaRush /Java Blog /Random-JA /10 Java の static 修飾子に関する注意事項

10 Java の static 修飾子に関する注意事項

Random-JA グループに公開済み
Java のstatic 修飾子はクラスに直接関連付けられます。フィールドが静的であれば、それはクラスに属し、メソッドが静的であれば、それは同じであり、クラスに属します。これに基づいて、クラス名を使用して静的メソッドまたはフィールドにアクセスできます。たとえば、Count フィールドが Counter クラスの静的な場合、Counter.count のようなクエリを使用して変数にアクセスできます。 10 Java の static 修飾子に関する注意事項 - 1注意事項を始める前に、静的とは何か、そして Java では何が静的になり得るのかを思い出してみましょう (おそらく調べてみましょう)。 static は、フィールド、ブロック、メソッド、または内部クラスに適用される修飾子です。この修飾子は、サブジェクトが現在のクラスにバインドされていることを示します。

静的フィールド

クラスレベル変数を示すときは、その値がクラスに属していることを示します。これを行わないと、変数の値は、このクラスを使用して作成されたオブジェクトにバインドされます。それはどういう意味ですか? 10 Java の static 修飾子に関する注意事項 - 2実際、変数が静的でない場合、このクラスの各新しいオブジェクトは、1 つのオブジェクト内で排他的に変更することによって、この変数の独自の値を持つことになります。たとえば、非変数を持つ Car クラスがあります。 -静的変数:
public class Car {
  int km;
}
次にメインで:
Car orangeCar = new Car();
orangeCar.km = 100;

Car blueCar = new Car();
blueCar.km = 85;

System.out.println("Orange car - " + orangeCar.km);
System.out.println("Blue car - " + blueCar.km);
得られる出力は次のとおりです。

Orange car - 100
Blue car - 85
ご覧のとおり、各オブジェクトには独自の変数があり、その変更はこのオブジェクトに対してのみ発生します。静的変数がある場合、このグローバル値は誰にとっても同じです。 これで、静的変数を持つ Car ができました。
public class Car {
  static int km;
}
次に、main の同じコードがコンソールに出力されます。

Orange car - 85
Blue car - 85
結局のところ、私たち全員に 1 つの変数があり、毎回それを変更します。静的変数は通常、オブジェクト参照 (orangeCar.km) ではなく、クラス名 (Car.km) によってアクセスされます。

静的ブロック

通常と静的という 2 つの初期化ブロックがあります。このブロックは内部変数を初期化することを目的としています。ブロックが正常であれば、オブジェクトの内部変数はそれで初期化されますが、静的であれば、静的変数 (つまり、クラス変数) が割り当てられます。静的初期化ブロックを含むクラスの例:
public class Car {
  static int km;

  static {
     km = 150;
  }
}

静的メソッド

静的メソッドは、オブジェクトではなくクラスにバインドされるという点でも通常のメソッドとは異なります。静的メソッドの重要な特性は、静的変数/メソッドのみにアクセスできることです。例として、メソッド呼び出しを追跡する一種のカウンターとなるクラスを見てみましょう。
public class Counter {
  static int count;

  public static void invokeCounter() {
     count++;
     System.out.println("Current counter value - " + count);
  }
}
main で呼び出してみましょう:
Counter.invokeCounter();
Counter.invokeCounter();
Counter.invokeCounter();
そして、コンソールに出力を取得します。

Текущее meaning счётчика - 1
Текущее meaning счётчика - 2
Текущее meaning счётчика - 3

Javaの静的クラス

内部クラスのみが静的クラスになれます。繰り返しますが、このクラスは外側のクラスに関連付けられており、外側のクラスが別のクラスに継承されると、このクラスは継承されません。さらに、このクラスは、他のクラスから継承してインターフェイスを実装できるのと同じように、継承することができます。基本的に、静的ネストされたクラスは、そのオブジェクトに、それを作成した外部クラス オブジェクトへの参照が含まれていないことを除いて、他の内部クラスと何ら変わりません。ただし、これにより、静的クラスは通常のネストされていないクラスに最も似たものになります。唯一の違いは、静的クラスが別のクラスにラップされることだけです。場合によっては、外部クラスのプライベート静的変数にアクセスできるため、これが利点となります。ネストされた静的クラスの例:
public class Vehicle {

  public static class Car {
     public int km;
  }
}
このクラスのインスタンスを作成し、内部変数の値を設定します。
Vehicle.Car car = new Vehicle.Car();
car.km = 90;
静的メソッド/変数/クラスを使用するには、そのクラスのオブジェクトを作成する必要はありません。もちろん、アクセス修飾子を考慮する必要があります。たとえば、フィールドは、privateそれが宣言されているクラス内でのみアクセスできます。フィールドは、protectedパッケージ ( package ) 内のすべてのクラスだけでなく、パッケージ外のすべての子孫クラスでも使用できます。詳細については、「プライベート vs 保護 vs パブリック」の記事をご覧ください。increment()クラス内に、Counterカウンタをインクリメントするタスクを持つ静的メソッドがあるとしますcount。このメソッドを呼び出すには、フォームの呼び出しを使用できますCounter.increment()Counter静的フィールドまたはメソッドにアクセスするためにクラスをインスタンス化する必要はありません。これが、静的オブジェクトと非静的オブジェクト (クラス メンバー) の基本的な違いです。静的クラスのメンバーは、インスタンスではなくクラスに直接属していることをもう一度思い出してください。つまり、静的変数の値は、count型のすべてのオブジェクトで同じになりますCounter。この記事の後半では、Java で static 修飾子を使用する基本的な側面と、主要なプログラミング概念を理解するのに役立ついくつかの機能について説明します。

Java の Static 修飾子についてすべてのプログラマーが知っておくべきこと

このセクションでは、静的メソッド、フィールド、クラスの使用の基本を見ていきます。変数から始めましょう。
  1. 静的コンテキスト内のクラスの非静的メンバー (メソッドやブロックなど) にアクセスすることはできません。以下のコードをコンパイルするとエラーが発生します。

    public class Counter{
    private int count;
    public static void main(String args[]){
       System.out.println(count); //compile time error
    }}

    これは、Java プログラマ、特に初心者が犯しやすい間違いの 1 つです。メソッドmainは静的ですが、変数は静的countではないため、この場合、printlnメソッド内のメソッドはmain「コンパイル時エラー」をスローします。

  2. В отличие от локальных переменных, статические поля и методы НЕ потокобезопасны (Thread-safe) в Java. На практике это одна из наиболее частых причин возникновения проблем связанных с безопасностью мультипоточного программирования. Учитывая что каждый экземпляр класса имеет одну и ту же копию статической переменной, то такая переменная нуждается в защите — «залочивании» классом. Поэтому при использовании статических переменных, убедитесь, что они должным образом синхронизированы (synchronized), во избежание проблем, например таких How «состояние гонки» (race condition).

  3. Статические методы имеют преимущество в применении, т.к. отсутствует необходимость каждый раз создавать новый an object для доступа к таким методам. Статический метод можно вызвать, используя тип класса, в котором эти методы описаны. Именно поэтому, подобные методы How нельзя лучше подходят в качестве методов-фабрик (factory), и методов-утorт (utility). Класс java.lang.Math — замечательный пример, в котором почти все методы статичны, по этой же причине классы-утorты в Java финализированы (final).

  4. Другим важным моментом является то, что вы НЕ можете переопределять (Override) статические методы. Если вы объявите такой же метод в классе-наследнике (subclass), т.е. метод с таким же именем и сигнатурой, вы лишь «спрячете» метод суперкласса (superclass) instead of переопределения. Это явление известно How сокрытие методов (hiding methods). Это означает, что при обращении к статическому методу, который объявлен How в родительском, так и в дочернем классе, во время компиляции всегда будет вызван метод исходя из типа переменной. В отличие от переопределения, такие методы не будут выполнены во время работы программы. Рассмотрим пример:

    class Vehicle{
         public static void  kmToMiles(int km){
              System.out.println("Inside parent class/static method");
         } }
    
    class Car extends Vehicle{
         public static void  kmToMiles(int km){
              System.out.println("Inside child class/static method ");
         } }
    
    public class Demo{
       public static void main(String args[]){
          Vehicle v = new Car();
           v.kmToMiles(10);
      }}

    Вывод в консоль:

    Внутри родительского класса/статического метода

    Код наглядно демонстрирует: несмотря на то, что an object имеет тип Car, вызван статический метод из класса Vehicle, т.к. произошло обращение к методу во время компиляции. И заметьте, ошибки во время компиляции не возникло!

  5. Объявить статическим также можно и класс, за исключением классов верхнего уровня. Такие классы известны How «вложенные статические классы» (nested static class). Они бывают полезными для представления улучшенных связей. Яркий пример вложенного статического класса — HashMap.Entry, который предоставляет структуру данных внутри HashMap. Стоит заметить, также How и любой другой внутренний класс, вложенные классы находятся в отдельном файле .class. Таким образом, если вы объявor пять вложенных классов в вашем главном классе, у вас будет 6 файлов с расширением .class. Ещё одним примером использования является объявление собственного компаратора (Comparator), например компаратор по возрасту (AgeComparator) в классе сотрудники (Employee).

  6. Модификатор static также может быть объявлен в статичном блоке, более известным How «Статический блок инициализации» (Static initializer block), который будет выполнен во время загрузки класса. Если вы не объявите такой блок, то Java соберёт все статические поля в один список и выполнит его во время загрузки класса. Однако, статичный блок НЕ может пробросить перехваченные исключения, но может выбросить не перехваченные. В таком случае возникнет «Exception Initializer Error». На практике, любое исключение возникшее во время выполнения и инициализации статических полей, будет завёрнуто Java в эту ошибку. Это также самая частая причина ошибки «No Class Def Found Error», т.к. класс не находился в памяти во время обращения к нему.

  7. Полезно знать, что статические методы связываются во время компиляции, в отличие от связывания виртуальных or не статических методов, которые связываются во время исполнения на реальном an objectе. Следовательно, статические методы не могут быть переопределены в Java, т.к. полиморфизм во время выполнения не распространяется на них. Это важное ограничение, которое необходимо учитывать, объявляя метод статическим. В этом есть смысл, только тогда, когда нет возможности or необходимости переопределения такого метода классами-наследниками. Методы-фабрики и методы-утorты хорошие образцы применения модификатора static. Джошуа Блох выделил несколько преимуществ использования статичного метода-фабрики перед конструктором, в книге «Effective Java», которая является обязательной для прочтения каждым программистом данного языка.

  8. Важным свойством статического блока является инициализация. Статические поля or переменные инициализируются после загрузки класса в память. Порядок инициализации сверху вниз, в том же порядке, в Howом они описаны в исходном файле Java класса. Поскольку статические поля инициализируются на потокобезопасный манер, это свойство также используется для реализации паттерна Singleton. Если вы не используется список Enum How Singleton, по тем or иным причинам, то для вас есть хорошая альтернатива. Но в таком случае необходимо учесть, что это не «ленивая» инициализация. Это означает, что статическое поле будет проинициализировано ещё ДО того How кто-нибудь об этом «попросит». Если an object ресурсоёмкий or редко используется, то инициализация его в статическом блоке сыграет не в вашу пользу.

  9. シリアル化中、変数と同様にtransient、静的フィールドはシリアル化されません。実際、静的フィールドにデータを保存すると、逆シリアル化後、新しいオブジェクトにはそのプライマリ (デフォルト) 値が含まれます。たとえば、静的フィールドが 型の変数の場合、逆intシリアル化後の値はゼロになります。タイプが–の場合、タイプfloatは 0.0 です。正直なところ、これは Java のインタビューでシリアル化に関して最もよく聞かれる質問の 1 つです。オブジェクトに関する最も重要なデータを静的フィールドに保存しないでください。Objectnull

  10. そして最後に、 について話しましょうstatic import。この修飾子は標準の演算子と多くの共通点がありますimportが、それとは異なり、クラスの 1 つまたはすべての静的メンバーをインポートできます。静的メソッドをインポートするときは、同じクラスで定義されているかのようにアクセスできます。同様に、フィールドをインポートするときは、クラス名を指定せずにアクセスできます。この機能は Java バージョン 1.5 で導入され、適切に使用するとコードの可読性が向上します。この構造はJUnitテストで最もよく見られます。ほとんどすべてのテスト開発者はstatic import、たとえば、assert メソッドassertEquals()とそのオーバーロードされた複製を使用します。明確な点が何もない場合は、追加情報を歓迎します

それだけです。すべてのプログラマは、Java の static 修飾子に関する上記の点をすべて理解しておく必要があります。この記事では、静的変数、フィールド、メソッド、初期化ブロック、インポートに関する基本的な情報について説明しました。いくつかの重要なプロパティが含まれており、Java でプログラムを作成および理解する際にその知識が不可欠です。すべての開発者が静的概念を使用するスキルを磨くことを願っています。なぜなら... これは本格的なプログラミングにとって非常に重要です。」
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION