ぱぴブログ

さんたろのブログ

ゲーム開発が好きな人のひとりごと

Java奮闘記2 クラス

はじめに

環境などは以下の記事を参考にしてほしい。
papyrustaro.hatenablog.jp

クラス

クラスとオブジェクト

フィールドとメソッド

状態の持ち方と振る舞いをクラスが規定。
・状態の持ち方→フィールド
・振る舞い→メソッド

Musicクラス

public class Music{
	//フィールド
	String title;
	String author;
	
	//メソッド
	void printData() {
		System.out.println("Title: " + this.title);
		System.out.println("Author: " + this.author);
	}
}
public static void main(String[] args) {
	Music music = new Music();
		
	music.title = "Hopes and Dreams";
	music.author = "Toby Fox";
		
	music.printData();
}

既存クラスの利用

new式による生成
//new クラス名(コンストラクタの実引数)
StringBuilder sb = new StringBuilder("ABC");
Stringリテラル表記による暗黙の生成
String s = "ABC";
オートボクシングによる暗黙の生成
Integer n = 10;

クラスの構成要素

・フィールド
・クラスフィールド
・メソッド
・クラスメソッド
・内部クラス
・staticなネストしたクラス
・staticなネストしたインターフェース
・コンストラク
・初期化ブロック
・static初期化ブロック

同一クラス内のフィールド変数のスコープ

フィールド変数のスコープは宣言した行以降。
ただし、同一クラスの全てのコンストラクタとメソッド内では行以前でも可能。

アクセス修飾子

・public ... 全てのクラスからアクセス可能
・protected ... 現在のクラスとサブクラスからアクセス可能
・デフォルト ... 現在のパッケージと同じパッケージのクラスからアクセス可能
・private ... 現在のクラスからのみアクセス可能

this参照

this参照は該当クラスのオブジェクトを参照する参照型変数。

・メソッド内のthis参照 → メソッド呼び出し対象のオブジェクト(レシーバオブジェクト)
・コンストラクタ、初期化ブロック、フィールド宣言の初期値 → 生成中のオブジェクト

クラス内での変数名の検索はフィールド変数よりローカル変数とパラメータ変数を優先される。
→隠蔽されたフィールド変数を使うためにthis.を明示。

private final String s = "Undertale";
	
void method(String s) {
	System.out.println(s); //パラメータ変数
	System.out.println(this.s); //フィールド変数
}
	
void method2() {
	String s = "CORE";
	System.out.println(s); //ローカル変数
        System.out.println(this.s); //フィールド変数
}

メソッド

メソッドのスコープ

メソッドのスコープはクラス内。メソッド宣言より前の行でも有効。
フィールドアクセス同様、this参照を使うことも可能。
他のクラス内からのメソッド呼び出しはアクセス修飾子による。

メソッドに使う用語

・パラメータ変数 ... 仮引数
・パラメータ ... 実引数
・ローカル変数 ... メソッド内で宣言した変数。

可変長引数

最後の仮引数の型に...を付けると可変長引数になる。
可変長引数は任意の数の実引数(なくてもよい)で呼ぶことができる。

Sampleクラス

public class Sample{
	public void func(String... messages) {
		for(String s : messages) {
			System.out.println(s);
		}
	}
	public void func2(int n, double... ds) {
		System.out.println(n);
		for(double x : ds) {
			System.out.println(x);
		}
	}
}

Samplerクラス

public class Sampler{
	public static void main(String[] args) {
		Sample sample = new Sample();
		sample.func();
		sample.func("Hello");
		sample.func("Hello", "Java", "World");
		
		sample.func2(1);
		sample.func2(2, 3.3);
		sample.func2(3, 4.4, 5.5, 6.6);
	}
}
シグネチャ

シグネチャ: クラス内のメソッドを区別する最小情報。
シグネチャメソッド名引数の型の並びで決まる。

コンストラク

コンストラクタはオブジェクトが生成されたときに呼ばれる。
基本的には、パラメータ変数を使ったフィールド変数の初期化をおこなう。

this、super呼び出し

具体例のみあげる。

this呼び出し

public class Music{
	String title;
	String author;
	int price;
	
	Music(String title, String author, int price){
		this.title = title;
		this.author = author;
		this.price = price;
	}
	
	Music(String title){
		this(title, "名無し", 0);
	}
	
	Music(){
		this("タイトル", "名無し", 0);
	}
}

super呼び出し(上記のMusicクラスを受けて)

public class Anison extends Music{
	private final String anime_title;
	
	Anison(String title, String author, int price, String anime_title){
		super(title, author, price);
		this.anime_title = anime_title;
	}
}
デフォルトコンストラク

コンストラクタ宣言を1つも書いていないクラスには、
引数なし、中身が空(継承元のsuper呼び出し以外)のデフォルトコンストラクタが自動生成される。

しかし、デフォルトコンストラクタはコンストラクタを1つでも書くと消滅するため、
エラーの元となる。

そのため、常にコンストラクタを書き、デフォルトコンストラクタは使わないことが大事。

初期化ブロック

クラス中に初期化ブロックを書くと、オブジェクトの初期化時に実行される。
・すべてのコンストラクタの共通処理
・匿名クラスの初期化
この2点で利用する。

public class Music{
	private final int price;
	
	//初期化ブロック
	{
		price = 5;
		System.out.println(price);
	}
	
	//初期化ブロック以外でメソッド呼び出しは書けない
	System.out.println(price); //コンパイルエラー
}
オブジェクト初期化処理の順序

フィールド変数にデフォルト値代入

フィールド変数宣言時の初期化、初期化ブロックの実行(コード上から)

コンストラクタ呼び出し

staticメンバ

・クラスフィールド(変数) ... static修飾子がついたフィールド(変数)
インスタンスフィールド(変数) ... static修飾子がついていないフィールド(変数)
・クラスメソッド ... static修飾子がついたメソッド

クラスフィールドとクラスメソッドの利用

・ユーティリティクラスのメソッド
・クラスの役割に関連する状態や操作(オブジェクトの生成数を数えるなど)
これらに限定すべき。

拡張継承

コードは this、super呼び出しを参照

拡張継承によるクラスの構成要素の追加、削除

・追加 ... 可能
・削除 ... 不可能

フィールド変数の隠蔽

継承したクラスで継承元と同名のフィールド変数を宣言すると、
継承元のフィールド変数を隠蔽する。
一般に変数の隠蔽は避けるべき。

super参照

オーバーライドされた元メソッドや隠蔽されたフィールド変数は、
super参照を通じて呼び出すことができる。

class Base{
	final String s = "111";
	void exec() {
		System.out.println(s + "fromB");
	}
}

class Inheritance extends Base{
	private final String s = "222";
	
	@Override
	void exec() {
		super.exec();
		System.out.println(s + "fromI");
	}
	
	public static void main(String[] args) {
		Base base = new Base();
		base.exec(); /// 111fromB
		
		Inheritance inh = new Inheritance();
		inh.exec(); /// 111fromB
		           /// 222fromI
		
		Base inh2 = new Inheritance();
		inh2.exec(); /// 111fromB
		            /// 222fromI
	}
}
抽象クラスと抽象メソッド

・抽象クラス ... インスタンス化できないクラス。abstract修飾子を付ける。

abstract class Base{
	protected abstract int doTask(int n);
	
	void exec(int n) {
	    n = doTask(n);
	    System.out.println(n);
	}
}

class Inh1 extends Base{
    @Override
    protected int doTask(int n) {
        return n * 2;
    }
}

class Inh2 extends Base{
    @Override
    protected int doTask(int n) {
        return n * n;
    }
}

class Tester{
    public static void main(String[] args) {
        Inh1 inh1 = new Inh1();
        Inh2 inh2 = new Inh2();
        
        inh1.exec(10); //20
        inh2.exec(10); //100
    }
}

関連記事

papyrustaro.hatenablog.jp
↑前回
次回↓
papyrustaro.hatenablog.jp