静的フィールド
クラスレベル変数を示すときは、その値がクラスに属していることを示します。これを行わないと、変数の値は、このクラスを使用して作成されたオブジェクトにバインドされます。それはどういう意味ですか? 実際、変数が静的でない場合、このクラスの各新しいオブジェクトは、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 修飾子についてすべてのプログラマーが知っておくべきこと
このセクションでは、静的メソッド、フィールド、クラスの使用の基本を見ていきます。変数から始めましょう。-
静的コンテキスト内のクラスの非静的メンバー (メソッドやブロックなど) にアクセスすることはできません。以下のコードをコンパイルするとエラーが発生します。
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
「コンパイル時エラー」をスローします。 -
В отличие от локальных переменных, статические поля и методы НЕ потокобезопасны (Thread-safe) в Java. На практике это одна из наиболее частых причин возникновения проблем связанных с безопасностью мультипоточного программирования. Учитывая что каждый экземпляр класса имеет одну и ту же копию статической переменной, то такая переменная нуждается в защите — «залочивании» классом. Поэтому при использовании статических переменных, убедитесь, что они должным образом синхронизированы (synchronized), во избежание проблем, например таких How «состояние гонки» (race condition).
-
Статические методы имеют преимущество в применении, т.к. отсутствует необходимость каждый раз создавать новый an object для доступа к таким методам. Статический метод можно вызвать, используя тип класса, в котором эти методы описаны. Именно поэтому, подобные методы How нельзя лучше подходят в качестве методов-фабрик (
factory
), и методов-утorт (utility
). Классjava.lang.Math
— замечательный пример, в котором почти все методы статичны, по этой же причине классы-утorты в Java финализированы (final
). -
Другим важным моментом является то, что вы НЕ можете переопределять (
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
, т.к. произошло обращение к методу во время компиляции. И заметьте, ошибки во время компиляции не возникло! -
Объявить статическим также можно и класс, за исключением классов верхнего уровня. Такие классы известны How «вложенные статические классы» (
nested static class
). Они бывают полезными для представления улучшенных связей. Яркий пример вложенного статического класса —HashMap.Entry
, который предоставляет структуру данных внутриHashMap
. Стоит заметить, также How и любой другой внутренний класс, вложенные классы находятся в отдельном файле .class. Таким образом, если вы объявor пять вложенных классов в вашем главном классе, у вас будет 6 файлов с расширением .class. Ещё одним примером использования является объявление собственного компаратора (Comparator
), например компаратор по возрасту (AgeComparator
) в классе сотрудники (Employee
). -
Модификатор static также может быть объявлен в статичном блоке, более известным How «Статический блок инициализации» (
Static initializer block
), который будет выполнен во время загрузки класса. Если вы не объявите такой блок, то Java соберёт все статические поля в один список и выполнит его во время загрузки класса. Однако, статичный блок НЕ может пробросить перехваченные исключения, но может выбросить не перехваченные. В таком случае возникнет «Exception Initializer Error». На практике, любое исключение возникшее во время выполнения и инициализации статических полей, будет завёрнуто Java в эту ошибку. Это также самая частая причина ошибки «No Class Def Found Error», т.к. класс не находился в памяти во время обращения к нему. -
Полезно знать, что статические методы связываются во время компиляции, в отличие от связывания виртуальных or не статических методов, которые связываются во время исполнения на реальном an objectе. Следовательно, статические методы не могут быть переопределены в Java, т.к. полиморфизм во время выполнения не распространяется на них. Это важное ограничение, которое необходимо учитывать, объявляя метод статическим. В этом есть смысл, только тогда, когда нет возможности or необходимости переопределения такого метода классами-наследниками. Методы-фабрики и методы-утorты хорошие образцы применения модификатора static. Джошуа Блох выделил несколько преимуществ использования статичного метода-фабрики перед конструктором, в книге «Effective Java», которая является обязательной для прочтения каждым программистом данного языка.
-
Важным свойством статического блока является инициализация. Статические поля or переменные инициализируются после загрузки класса в память. Порядок инициализации сверху вниз, в том же порядке, в Howом они описаны в исходном файле Java класса. Поскольку статические поля инициализируются на потокобезопасный манер, это свойство также используется для реализации паттерна
Singleton
. Если вы не используется списокEnum
HowSingleton
, по тем or иным причинам, то для вас есть хорошая альтернатива. Но в таком случае необходимо учесть, что это не «ленивая» инициализация. Это означает, что статическое поле будет проинициализировано ещё ДО того How кто-нибудь об этом «попросит». Если an object ресурсоёмкий or редко используется, то инициализация его в статическом блоке сыграет не в вашу пользу. -
シリアル化中、変数と同様に
transient
、静的フィールドはシリアル化されません。実際、静的フィールドにデータを保存すると、逆シリアル化後、新しいオブジェクトにはそのプライマリ (デフォルト) 値が含まれます。たとえば、静的フィールドが 型の変数の場合、逆int
シリアル化後の値はゼロになります。タイプが–の場合、タイプfloat
は 0.0 です。正直なところ、これは Java のインタビューでシリアル化に関して最もよく聞かれる質問の 1 つです。オブジェクトに関する最も重要なデータを静的フィールドに保存しないでください。Object
null
-
そして最後に、 について話しましょう
static import
。この修飾子は標準の演算子と多くの共通点がありますimport
が、それとは異なり、クラスの 1 つまたはすべての静的メンバーをインポートできます。静的メソッドをインポートするときは、同じクラスで定義されているかのようにアクセスできます。同様に、フィールドをインポートするときは、クラス名を指定せずにアクセスできます。この機能は Java バージョン 1.5 で導入され、適切に使用するとコードの可読性が向上します。この構造はJUnitテストで最もよく見られます。ほとんどすべてのテスト開発者はstatic import
、たとえば、assert メソッドassertEquals()
とそのオーバーロードされた複製を使用します。明確な点が何もない場合は、追加情報を歓迎します。
GO TO FULL VERSION