Javaで親クラスの変数・メソッドに子クラスからアクセスする方法が知りたい
superの使い方をマスターしたい
Javaで親クラスの変数やメソッドに子クラスからアクセスしたいと思ったことはありませんか?
そんなときは、「super」を使えば子クラスから親クラスの変数やメソッドを参照することができます。
この記事では、Javaのsuperについて、意味や使い方、thisとの違いについて、わかりやすく解説いたします。
superの基本から応用的な使い方まで網羅していますので、ぜひ参考にしてください。
なお、Javaの記事については、こちらにまとめています。
Javaのsuperとは
superとは、Javaにおけるサブクラスでオーバーライド(親クラスのメソッドを子クラスで継承)された変数やインスタンスを参照する場合に使用されます。
つまり、子クラスのインスタンス(new [クラス名()]で作られたクラスの実体のこと)から、親クラスのインスタンスのメンバにアクセスして、値を参照する必要があるときにsuperが使用されます。
superの基本的な使い方
ここでは、superを理解するのに必須のクラスの継承から、superの基本的な使い方を説明します。
クラスの継承の復習
superの使い方に入る前に、extends(継承)の使い方についても触れておきましょう。クラスの継承とは、例えばクラスFruitClassがあったとして、そのFruitClassを継承したAppleClassを作るとします。
クラスの継承するときは「extends クラス名」で指定します。
//親クラス class FruitClass{ FruitClass(){ } } //子クラス class AppleClass extends FruitClass{ AppleClass(){ } }
クラスを継承することで、FruitClassは親クラスとなり、AppleClassは子クラスとなります。つまり、親クラスを継承することで、子クラスであるAppleClassからは、親クラスのインスタンスや変数にアクセスすることが可能になります。
以下に実際にクラスの継承を使用したサンプルを紹介します。
public class Main { public static void main(String[] args) throws Exception { ApplePieClass applepie = new ApplePieClass(); } } class FruitClass{ FruitClass(){ System.out.println("FruitClass"); } } class AppleClass extends FruitClass{ AppleClass(){ System.out.println("AppleClass"); } } class ApplePieClass extends AppleClass{ ApplePieClass(){ System.out.println("ApplePieClass"); } }
[実行結果]
FruitClass AppleClass ApplePieClass
サンプルでは、親クラスであるFruitClassと親クラスを継承した子クラスであるAppleClass、さらにAppleClassを継承したApplePieClassクラスがあります。
MainメソッドからApplePieClassのインスタンスを作成すると、継承元の親クラスであるAppleClassクラスとさらにその親クラスであるFruitClassが参照されます。
つまり、一番上層の親クラスから順に参照されるため、実行結果のように出力されます。
クラスの継承についてはこちらの記事で解説しているので、ぜひ確認してください!
親クラスのコンストラクタを呼び出す
前述したクラスの継承を踏まえて、superの基本的な使い方を見ていきましょう。
以下に子クラスから親クラスをsuperで呼び出して、実行結果を出力するサンプルを紹介します。
public class Main { public static void main(String[] args) throws Exception { SubClass sub = new SubClass(); } } class SuperClass { public SuperClass(){ System.out.println("Super_Const"); } public SuperClass(String str){ System.out.println("str : " + str); } public SuperClass(int num){ System.out.println("num : " + num); } } class SubClass extends SuperClass { public SubClass(){ super("apple"); } }
[実行結果]
str : apple
サンプルでは親クラスであるSuperClassと子クラスであるSubClassを作成し、extendsでSuperClassを継承しています。
Subクラスのコンストラクタから、superを使用して引数で文字列”apple”を指定しています。
親クラスには3つの引数の異なる(引数なし、String型、int型)コンストラクタがありますが、子クラスではsuperで文字列の引数を指定しているため、該当するString型の引数があるコンストラクタが呼び出されています。
int型のコンストラクタを呼び出したい場合は、super(int型)を指定します。
親クラス(スーパークラス)の変数やメソッドを参照
ここでは、superで親クラス(スーパークラス)の変数やメソッドを参照する方法を解説します。
子クラス(サブクラス)で、オーバーライドを行った場合にはメソッド名が同じになるので、そのままでは親クラスのメソッドを呼び出すことができません。
このときに、superを使って親クラスのオーバーライドされていないメソッドを呼び出すことができます。同様に、superを使って同じ変数名の隠蔽された親クラスの変数を参照することができます。
次のプログラムで確認してみましょう。
class SuperClassSample { String str = "SuperClass"; public String getSrt() { return str; } } class SubClassSample extends SuperClassSample { String str = "SubClass"; public String getSrt() { return str; } public void print() { System.out.println("super.str = " + super.str); System.out.println("str = " + str); System.out.println("super.getSrt() = " + super.getSrt()); System.out.println("getSrt() = " + getSrt()); } } public class Main { public static void main(String[] args) { SubClassSample scs = new SubClassSample(); scs.print(); } }
[実行結果]
super.str = SuperClass str = SubClass super.getSrt() = SuperClass getSrt() = SubClass
このプログラムの実行結果から、superを使うと親クラスの変数の値が表示され、superを使わない場合には子クラスの値が表示されることが確認できます。
同様に、superを使うと親クラスのメソッドが呼び出され、superを使わない場合には子クラスのメソッドが呼び出されることが確認できます。
このようにsuperを使うことで、オーバーライドした場合にも親クラスのメソッドや、隠蔽された変数を参照できることが確認できました!
superの応用的な使い方
cloneのsuperとは
Javaの全ての親クラスには、オブジェクトを複製するためのcloneメソッドが用意されています。cloneメソッドを使用することにより、自分自身のクラスを複製することができます。
例えば、片方のクラスを操作して変数の内容が変わっても、cloneメソッドを使用してクラスの複製を作っておけばもう1つのクラスは内容が変わることがありません。
cloneメソッドを使用するには、Cloneableインターフェース(implements)を実装する必要があります。
Cloneableインターフェースを実装する際に、クラスのフィールドに普遍オブジェクトがある場合は、cloneメソッドの中身はsuper.clone()を呼び出します。
以下にcloneメソッドを使用した簡単な使用例を記述します。
class Clone_Test implements Cloneable { public int num = 0; public Clone_Test clone() { try { // クラスの複製を生成 Clone_Test ct = (Clone_Test) super.clone(); num = 10; System.out.println("num : " + num); System.out.println("ct.num : " + ct.num); return (Clone_Test) super.clone(); } catch (Exception ex) { throw new AssertionError(); } } } public class Main { public static void main(String[] args) { Clone_Test c = new Clone_Test(); c.clone(); } }
[実行結果]
num : 10 ct.num : 0
サンプルではClone_Testの複製を作成し、その後変数numの値を変更しています。
実行結果からわかるように、cloneメソッドで複製したClone_Testクラスのctが参照している、変数numの値が変わっていないことがわかります。
generics(ジェネリクス)のsuperとは
generics(ジェネリクス)とはクラスを作るときに、型の情報を変数として、汎用的に保持するためのJavaSE 6から登場した機能です。
superをgenericsとして指定する場合は「? super Integer」のように指定してあげれば、下限型つきのスーパータイプとなります。
この例では、クラスの上層への型指定となります。
<? super クラス名>
genericsは、扱い方が難しく初心者には不向きと言えます。
generics(ジェネリクス)についてはこちらの記事で詳しく解説しているので、ぜひ確認してください。
superとthisの違いと使い方
superは親クラスの変数やコンストラクタにアクセスできるのに対して、thisは自分のクラスの変数やメソッドにアクセスするために使用します。
以下にsuperとthisの違いがわかるサンプルを紹介します。
public class Main { public static void main(String[] args) throws Exception { SubClass sub = new SubClass(); } } class SuperClass { String str = "Super"; } class SubClass extends SuperClass { String str = "Sub"; public SubClass(){ System.out.println("super.str : " + super.str); System.out.println("this.str : " + this.str); } }
[実行結果]
super.str : Super this.str : Sub
実行結果からわかるようにsuperを指定すると親クラスの変数を、thisを使用すると自分のクラスの変数を参照していることがわかります。
thisの使い方については、以下の記事で詳しく解説しています!
まとめ
ここでは、Javaにおけるsuperの役割や使い方などを説明しました。
superは、親クラスのインスタンスや変数を参照するのに便利ですので、ぜひ覚えておきましょう。
もし、superの使い方を忘れてしまったら、この記事を思い出してくださいね!