前回までのあらすじ
プログラミングド素人のデザイナーがJava入門してみた_その5
static修飾子
- インスタンス化しなくても使えるフィールドやメソッドを登録できる
private static 型 変数名 = 値;
-
static
のついたフィールドやメソッドを、クラス変数やクラスメソッドという - クラス変数の値はインスタンスではなくクラスに紐づく
- インスタンス化された数とかを保持できる
- クラス変数はクラスに紐づくので、アクセスする場合は**
クラス名.フィールド名
**とする
Hoge.huga //this.hugaではだめ
###インスタンス化された回数を表示してみる
class User{
private String name;
//★インスタンス化された回数を保持するstaticフィールド
private static int count = 0;
public User(String name){//コンストラクタ
this.name = name;
//★クラス内からstaticフィールドにアクセスするときは[クラス名].[フィールド名]とする
User.count++;//インスタンス化されるたび(正確にはコンストラクタが実行されるたび)+1する
}
//★インスタンス化された回数を表示するstaticメソッド
public static void getInfo(){
System.out.println(User.count);
}
}
public class HelloWorld {
public static void main(String[] args) {
//staticメソッドなのでインスタンス化せずに使える
User.getInfo();//0
User bob = new User("Bob");//インスタンス化
User.getInfo();//1
}
}
- 起点となる
main()
がstatic
となっているのは、javaの仮想マシンがインスタンス化せず直接実行できるようにするため
public class HelloWorld {
public static void main(String[] args) {//main()もstaticメソッド
処理
}
}
##イニシャライザ
- インスタンスに対するコンストラクタのように、クラスを使う前に実行されるメソッドを定義できる
staticイニシャライザ | インスタンスイニシャライザ | コンストラクタ |
---|---|---|
クラス宣言に伴い、最初に1度だけ実行される | newされる度、インスタンス化される前に実行される | newされる度、インスタンス化された後に実行される |
- 実行順はstaticイニシャライザ→インスタンスイニシャライザ→コンストラクタの順
###staticイニシャライザ
- 主にクラス変数の初期化に使う
static{
処理
}
###インスタンスイニシャライザ
- コンストラクタがオーバーロードされていて複数あったりする場合(newするときの引数によってコンストラクタの挙動が異なる場合?)共通処理を行ったりする
{//{から初めて処理を記述する
処理
}
###記述例
class User{
private String name;
private static int count;
//staticイニシャライザ
static { //主にクラス変数の初期化に使う
User.count = 0;
System.out.println("staticイニシャライザが実行された");
}
//インスタンスイニシャライザ
{
System.out.println("インスタンスイニシャライザが実行された");
}
public User(String name){//コンストラクタ
this.name = name;
System.out.println("コンストラクタが実行された");
}
}
public class HelloWorld {
public static void main(String[] args) {
User bob = new User("Bob");
}
}
##final修飾子
- クラスやフィールド、メソッドなどの変更を不可にする
クラス | フィールド | メソッド |
---|---|---|
継承不可 |
static と合わせて定数とする(書き換え不可) |
オーバーライド不可 |
- 修飾子の記述順に決まりはないが、アクセス修飾子→static→finalの順が一般的
final class User{//★finalで継承不可に
protected String name;
//staticとfinalを付与して定数とする
private static final double VERSION = 1.1;//★finalで変更不可に
public User(String name){//コンストラクタ
this.name = name;
User.VERSION = 1.2;//☆VERSIONは変更不可(定数)なのでコンパイルエラー
}
public final void sayHi(){//★finalでオーバーライド不可に
System.out.println("Hi! " + this.name);
}
}
class AdminUser extends User{//☆Userは継承不可なのでコンパイルエラー
public AdminUser(String name){//コンストラクタ
super(name);
}
@Override
public void sayHi(){//☆sahHiはオーバーライド不可なのでコンパイルエラー
System.out.println("[AdminUser]Hi! " + this.name);
}
}
public class HelloWorld {
public static void main(String[] args) {
User bob = new User("Bob");
}
}
定数
- 値の変更ができない変数
- 宣言時にかならず初期化(値をいれる)
- 定数名は慣習的にすべて大文字にする
-
final
とあわせてstatic
を付与するのは、変更不可であるためインスタンスごとに持たせる意味がなく、クラスで一元管理した方が効率がいいから(?)
抽象クラス
- 他のクラスに継承されることが前提のクラス
- これ単体をインスタンス化することは不可
- 抽象クラスを継承するクラスを具象クラスという
abstract class User{ //★abstractで抽象クラスとして宣言
//★メソッドの定義だけしておいて、実装は具象クラスに任せる
//★メソッドにabstractをつけることで、具象クラスでの実装(オーバーライド)を義務付ける
public abstract void sayHi();//抽象メソッド
}
class JapaneseUser extends User{//具象クラス
@Override
public void sayHi(){//抽象クラスで実装を義務付けられたメソッドを実装(オーバーライド)
System.out.println("こんにちは!");
}
}
class AmericanUser extends User{//具象クラス
@Override
public void sayHi(){//抽象クラスで実装を義務付けられたメソッドを実装(オーバーライド)
System.out.println("Hi!");
}
}
public class HelloWorld {
public static void main(String[] args) {
JapaneseUser tarou = new JapaneseUser();
AmericanUser john = new AmericanUser();
tarou.sayHi();//こんにちは!
john.sayHi();//Hi!
}
}
###抽象メソッド
- 抽象クラス内で宣言のみ行い、具象クラスでの実装(オーバーライド)が義務付けられたメソッド
##インターフェース
- クラスを拡張するための追加機能郡(クラスの簡易版みたいなもの?)
- 継承と異なりいくつでもくっつけることができるので、柔軟な機能追加ができる
- インターフェースには下記の要素が盛り込める
定数 | 抽象メソッド | defaultメソッド | staticメソッド |
---|---|---|---|
private ,static ,final を省略可 |
public ,abstruct を省略可 |
インターフェース自体に実装するメソッド | defaultメソッドが複雑になった場合に処理をまとめたりするヘルパー的存在のメソッド |
interface CanSayBye {//★interfaceを付与し、インターフェースとして宣言
//定数
double VERSION = 1.1;//private,static,final省略可
//抽象メソッド
void sayBye();//public,abstract省略可
//defaultメソッド
public default void getInfo(){
System.out.println("version " + CanSayBye.VERSION);
}
}
interface CanJump {//★もうひとつインターフェースを定義
void jump();
}
class User implements CanSayBye,CanJump{//★implementsを付与し、インターフェースをくっつける
@Override
public void sayBye(){
System.out.println("Bye...");
}
@Override
public void jump(){
System.out.println("JUMP!");
}
}
public class HelloWorld {
public static void main(String[] args) {
User bob = new User();
bob.sayBye();//bye...
bob.jump();//JUMP!
}
}
教科書
ドットインストールさまさま
@iwashi0830はこう思った
- クラス変数やクラスメソッドがあるなら、変数やメソッド単体で記述するケースはほぼない?
- イニシャライザの恩恵は、複雑な処理をする必要性がでてくるまで感じられなさそう
- 定数にstaticを付与する考え方は合理的でおもしろいとおもった
- わざわざ抽象クラスにする意味がよくわからん...
- インターフェースはあとから機能を付けたくなった時さくっと使える便利な技?
- のちのち機能を統合したほうがいい?