static
静的メンバ(static member)
staticキーワードが付けられた「フィールド(field)」や「メソッド」のこと
フィールド(field)ってどこ?
public class Hoge {
String lastName; // フィールド
int age = 20; // 初期値を設定したフィールド
final String FIRST_NAME = "山田" // フィールドを定数として宣言
static String address; // 静的フィールド(staticが付いている)
public void huga() {
System.out.println(this.age); // this.ageが自分自身のageフィールド
}
}
メンバ(member)とは?
フィールドとメソッドのこと
静的フィールド(static field)
- オブジェクト指向の基本原則に、インスタンスの独立性がある。
しかし、クラスを作成していると、「同じクラスから生成されたインスタンスでフィールドを共有したい場合」が出てくることがある。
この時に使うのが、staticキーワード。
インスタンスの独立性とは
- インスタンスの独立性とは
- newによって生成される個々のインスタンスは、基本的に独立した存在であること
(各インスタンスはそれぞれ別物である)- それぞれのインスタンスのフィールドも、それぞれ別な値を格納することができる
- newによって生成される個々のインスタンスは、基本的に独立した存在であること
- フィールドの先頭にstaticキーワードを付ける
- 同じクラスから生成されたインスタンスで、フィールドを共有できる
静的フィールド(static field)の効果
1. フィールド変数の実体がクラスに準備される
- 通常のフィールド:フィールドが格納される箱(領域)は、個々のインスタンス毎に用意される
- 静的フィールド:静的フィールドが格納される箱(領域)は、インスタンスではなくクラスに対して、1つだけ用意される
- ⭐静的フィールドへのアクセス方法
クラス名.静的フィールド名
- 静的フィールドへのアクセス方法 その2の以下と同じことができる
インスタンス変数瞑名.静的フィールド名
静的フィールドへのアクセス
public class Hoge {
String lastName; // フィールド
int age = 20; // 初期値を設定したフィールド
final String FIRST_NAME = "山田" // フィールドを定数として宣言
static String address; // 静的フィールド(staticが付いている)
public void huga() {
System.out.println(this.age); // this.ageが自分自身のageフィールド
}
}
public class Main {
public static void main(String[], args) {
Hoge hoge1 = new Hoge();
Hoge hoge2 = new Hoge();
System.out.println(hoge1.address); // ⭐静的フィールドaddressにアクセス
}
}
2. 全インスタンスに箱(領域)の分身が用意される
- ⭐静的フィールドへのアクセス方法 その2
インスタンス変数瞑名.静的フィールド名
- 静的フィールドへのアクセス方法の以下と同じことができる
クラス名.静的フィールド名
静的フィールドへのアクセス
public class Hoge {
static String address; // 静的フィールド(staticが付いている)
public void huga() {
System.out.println(this.age); // this.ageが自分自身のageフィールド
}
}
public class Main {
public static void main(String[], args) {
Hoge hoge1 = new Hoge();
Hoge hoge2 = new Hoge();
Hoge.address = "東京"; // 「クラス名.静的フィールド名」静的フィールドへのアクセス
System.out.println(Hoge.address); // 「クラス名.静的フィールド名」表示:東京
System.out.println(hoge1.address); // 「インスタンス変数名.静的フィールド名」表示:東京
hoge1.address = "沖縄"; // 「インスタンス変数名.静的フィールド名」静的フィールドへ沖縄を代入
System.out.println(hoge2.address); // 「インスタンス変数名.静的フィールド名」表示:沖縄
}
}
- 共通のフィールド(クラスフィールド)の値が変わる
- 静的フィールドを用いれば、インスタンス間でフィールドを共有できる
3. インスタンスを1つも生み出さなくても共有の箱(領域)が利用可能になる
- newしなくても、静的フィールドは利用可能
- 静的フィールドは、クラス(インスタンスを作るための金型)に、フィールド(箱)が所属するという特徴から。「クラス変数」とも言われることもある
staticの使い方
public static final コンビネーション
- 定数と一緒に宣言する
- 多くの場合、staticはfinalやpublicと一緒に指定される
- 「変化しない定数を各インスタンスで共有するため」に使用される
静的メソッド(static methot)(クラスメソッド)(class methot)
- staticが付いているメソッド
- 静的メンバ
静的メンバってなんだっけ?
静的メンバ(static member)
staticキーワードが付けられた「フィールド(field)」(静的フィールド)や「メソッド」(静的メソッド)のこと
静的メソッド(static methot)の効果
1. メソッド実体がクラスに属するようになる
- 静的メソッドは、その実態が各インスタンスではなくクラスに属するため、クラス名を使って呼び出せるようになる
2. インスタンスにメソッドの分身が準備される
- インスタンスにも分身が作られるため、インスタンス変数名からも呼び出すことができるようになる
- ⭐静的メソッドの呼び出し
クラス名.メソッド名();インスタンス変数名.メソッド名();
3. インスタンスを1つも生み出すことなく呼び出すことができる
- 静的フィールドと同時に、1つもインスタンスを生成していない状態でも静的メソッドは、呼び出し可能
- newをしなくても静的メソッドは呼び出し可能
mainメソッドはstaticでなくてはいけない
mainメソッドは最初に呼び出されて動く。
この時、仮想世界にはまだ1つもインスタンスが存在していない。
そのためmainメソッドは、インスタンスを1つも生成していなくても呼び出すことができるstaticメソッドにする必要がある。
静的メソッド(static methot)の制約
- 静的メソッドの中に記述するコードでは、同一クラスの内のstaticが付いているフィールドやメソッドのみ使用可能
- 同一クラスの内のstaticが付いていないフィールドやメソッドは利用不可(エラーになる)
- 理由:
- 静的メソッドはインスタンスが存在していない状態でも呼び出すことができる。
しかし、staticが付いていないメンバ(フィールドとメソッド)は、インスタンスが存在していないと呼び出すことができない。
つまり、staticが付いていないメンバ(フィールドとメソッド)を静的メソッド内で使おうとすると、「インスタンスが存在していないが、インスタンスが存在していないとエラーを起こすものを呼び出そうとしている」ことになり、エラーになる。
- 静的メソッドはインスタンスが存在していない状態でも呼び出すことができる。
静的メンバの使いどころ
- 静的メンバは、オブジェクト指向の基本原則である「インスタンスの独立性」に風穴を開ける仕組み
- オブジェクト指向の基本原則を崩す代償
- 不具合のリスクがある
- 静的メソッドの中では、静的フィールドしか使えない
- 静的フィールドは、フィールド内の内容を他のインスタンスから意図せず書き換えられる
- 同時アクセスされて破壊されたりする
- 不具合のリスクがある
- わざわざstaticを使わなくても、専用クラスを作ってそれぞれのインスタンスがそれを利用するようにすればいい(静的メンバを使う必要が無い)
- オブジェクト指向の基本原則を崩す代償
- 定数宣言や(public static final コンビネーション)やmainメソッド以外では、基本的に静的メンバを用いる機会がほとんどない
- JavaAPIでは、以下の理由から静的メンバを備えていることがある
-
理由1:newせずに手軽に呼び出すため
- 例)Integer.parseInt()メソッド
- 引数として与えられた文字列を数値に解釈して返すAPI
- 正確にはjava.lang.Integerクラスのメソッド。
しかし、静的メソッドとしてstaticが付いているため、Integerクラスをnewしなくても使用できる。- (newが不要だと人間(開発者)が楽になる。さらに、インスタンス生成にはCPUやメモリを多く消費するため、newが不要だとJVMにもメリットがある(リファレンスより))
- 例)Integer.parseInt()メソッド
-
理由2:newではなく、静的メソッドを使ってインスタンスを生成するため
- APIクラスの中には、コンストラクタがprivateで宣言されているものもある。
これらは、性能上または管理上の理由から「外部からのインスタンス化を禁止している」クラスである。
このような場合はほとんど「インスタンス生成を担うメソッド」が準備されている。
そのため、開発者は、そのメソッドを呼び出すことでインスタンスを生み出すことができる。
- APIクラスの中には、コンストラクタがprivateで宣言されているものもある。
-
おまけ
staticインポート
- static import 文
- import文を利用すると、あるクラスの静的メンバをインポートすることができる
import static パッケージ名.クラス名.静的メンバ名;
- 例)java.lang.Systemクラス
- 静的フィールドとしてoutを持っている。
そのため、「Import static java lang.System.:」と宣言しておくことで、「out.println(hoge);」で画面表示を行えるようにする。
- 静的フィールドとしてoutを持っている。
参考
- スッキリわかるJava入門 第3版
- 発売日:2019/11/15
- ページ番号:540~554頁
- 著者:中山 清喬 著/国本 大悟 著
公式リファレンス
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Integer.html#parseInt-java.lang.String-