【はじめてのJava】thisとsuperその1【クラスの継承編】
はじめてのJava
このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。
クラスの継承編
クラスの継承編では、Javaを扱う上で重要な「クラスの継承」について扱っていきます。
前回はオーバーライドの際のアクセス修飾子の注意点について扱いました。
今回はthisとsuperという2つのキーワードについて扱います。
目次
thisとsuper
Javaのプログラムを見ているとthisやsuperといったキーワードを見かけることがあります。
thisについてはコンストラクタの説明時などで何回か出てきました。
このthisやsuperとはいったいどのような意味のキーワードなのか、確認してみましょう。
thisとは
thisとは そのインスタンス自身のこと を指し示すキーワードです。
ちょっと言葉を変えると自分自身のというような意味合いになります。
変数の呼び出し時にthisを付ける場合
変数の呼び出し時にthisを付けることで、明示的にインスタンスであることを指し示せます。
例えば、Carクラスにspeedというインスタンス変数があるとします。
class Car { double speed; }
この時、sppedを10増やしたければ「speed += 10;」とも書けますが、「this.speed += 10;」と書くことも可能です。
class Car { double speed; void accell(){ speed += 10; //speedを10増加させる //this.speed += 10; //この書き方でも同じ動作になる } }
上記の例のようにspeedという変数が同じスコープ内に1つしかない場合はthisがあっても無くても動作は同じです。
しかし、以前の記事で紹介した通り、同じスコープ内に同名のインスタンス変数とローカル変数がいる場合は、thisなしで呼び出すとローカル変数の方を示すことになります。
インスタンス変数を呼び出すためには明示的にthisを付ける必要があります。
メソッドの呼び出し時にthisを付ける場合
メソッドの呼び出し時にthisを付けることで、明示的にそのインスタンス内のメソッドを呼び出していることを指し示せます。
詳しく説明する前に、まずは「インスタンス内のメソッドを呼び出す」という部分について確認しましょう。
インスタンス内のメソッドを呼び出す
アクセス修飾子が適切であれば、メソッド内で別のメソッドを呼び出すことは可能です。当然そのインスタンス自身のメソッドを呼び出すことも可能です。
具体例を見てみましょう。
例えば、Carクラスに通常のaccellメソッドのほかに、accellメソッド3回分と同じ動きをするturboAccellメソッドを実装するとします。
この時、例えば以下のように、turboAccellメソッド内でaccellメソッドと同じ動作を3回実行することもできます。
class Car { double speed; void accell(){ this.speed += 10; } void turboAccell(){ for(int i = 1; i <= 3; i++){ //for文で↓を3回繰り返す this.speed += 10; //accellメソッドと同じ動作 } } }
しかしこの場合、accellメソッドを書き換えてもturboAccellメソッドの内容は変更されません。
これは一概にいい悪いというものではありませんが、少なくともaccellメソッドを書き換えた場合はturboAccellメソッドはaccellメソッド3回分とは異なる動作になってしまいます。
もしaccellメソッドを書き換えても、turboAccellメソッドがaccellメソッド3回分の動作と同じ動き方になるようにしたい場合は turboAccellメソッドの中からaccellメソッドを呼び出せばよい ことになります。
そこで、先ほどのソースコードを以下のように直します。
class Car { double speed; void accell(){ this.speed += 10; } void turboAccell(){ for(int i = 1; i <= 3; i++){ //for文で↓を3回繰り返す //this.speed += 10; //accellメソッドと同じ動作 accell(); //accellメソッドそのものを呼び出す } } }
こうすることで、accellメソッドに加えた変更がtruboAccellメソッドの動作にも反映されるようになります。
thisを使ったメソッドの呼び出し
上記のように、自身のメソッドを呼び出すことができますが、この時thisをつけて呼び出すことも可能です。
上記の例を書き換えると、次のようになります。
class Car { double speed; void accell(){ this.speed += 10; } void turboAccell(){ for(int i = 1; i <= 3; i++){ //for文で↓を3回繰り返す //this.speed += 10; //accellメソッドと同じ動作 //accell(); //accellメソッドそのものを呼び出す this.accell(); //accellメソッドそのものを呼び出す } } }
このように、自分自身のメソッドを呼び出す際にもthisを利用することができます。
簡単なクラスではあまり恩恵がありませんが、クラスが大きくなってくると、後述のsuperとセットでうまく使うことでソースコードの見通しが良くなります。
コンストラクタの呼び出しでthisを利用する
以前コンストラクタの呼びなおしの際にthisを使っていました。
この時のthisも「自分自身の」という意味合いとなります。
なお、コンストラクタについては、自身のコンストラクタを呼びなおす場合は必ずthisを使う必要があります。
変数やメソッドと違ってthisなしで自身のコンストラクタを呼びなおすことはできません。
コラム:可読性への配慮
上記の通り、 thisがついている場合はインスタンス変数やインスタンスメソッドである ことが見た瞬間にわかります。
そのため、可読性を上げるためにインスタンス変数やインスタンスメソッドの呼び出しの際にthisを付けるというルールを採用している場合もあります。
サンプルプログラム
今回作成したサンプルプログラムは以下の通りです。また、動作確認用のDrive.javaも記載しておきます。
なお、すべて同じディレクトリに保存して動作を確認してください。
Car.java
class Car { double speed; void accell(){ this.speed += 10; } void turboAccell(){ for(int i = 1; i <= 3; i++){ //for文で↓を3回繰り返す //this.speed += 10; //accellメソッドと同じ動作 //accell(); //accellメソッドそのものを呼び出す this.accell(); //accellメソッドそのものを呼び出す } } }
Drive.java
public class Drive{ public static void main(String[] args){ Car car = new Car(); System.out.println(car.speed); car.turboAccell(); System.out.println(car.speed); } }
まとめ
thisとは「そのインスタンス自身のこと」を指すキーワード
次回
次回はsuperについて扱います。
はじめてのJavaシリーズの目次はこちら
クラスの継承編はこちら