
CONTENT
こんにちは、東京エンジニアSWです。
今回よりOracle Java Silverを受験予定の皆さんに向けて、対策講座をシリーズでお届けしたいと思います。
対象はJava Bronzeを取得した方、またはJava Bronze相当の方向けとします。
まず今回はクラスの継承について、問題になりやすい部分、間違えやすい部分をまとめました。
■クラスの継承
継承とはあるクラスのフィールドやメソッドを、別のクラスが引き継いでその機能を上書きできる仕組みです。
このとき継承される側をスーパークラス、継承する側をサブクラスといいます。
サブクラスではスーパークラスのPublic/Protected/(なし)のアクセス修飾子で定義されたメソッドの処理内容を上書きすることが可能で、このことをオーバーライドといいます。
※似た単語としてオーバーロードがありますが、これは別物ですので別の機会に解説します。
ここで注意しなくてはいけないのは、オーバーライドできるのはメソッドだけです。フィールドについては参照型で決まるためオーバーライドできません。
どういうことか見てみましょう。
class Super {
String name = "Super";
}
class Sub extends Super {
String name = "Sub";
}
public class Main {
public static void main(String[] args) {
Super c = new Sub();
System.out.println(c.name);
}
}
このコードの実行結果は「Super」と出力されます。
Subクラスのインスタンスを生成しているのになぜ?となるかもしれないですが、変数cの型がSuperクラスとして定義されているため、フィールドはSuperクラスを参照しているためです。
非常にややこしく試験でも頻出されるため、しっかりと抑えておきましょう。
■アクセス修飾子とオーバーライド
アクセス修飾子とはメソッド、フィールドの公開範囲を指します。以下のものがあり、下に行くほど公開範囲が広くなります。
・private
非公開。privateで定義されたメソッド/フィールドはそのクラス内でしか使用できない。オーバーライドも不可能。
・(なし)
限定公開。アクセス修飾子を省略したメソッド/フィールドは、同じパッケージ内であれば使用できる。
・protected
限定公開。protectedで定義されたメソッド/フィールドは、同じパッケージ内かサブクラス内で使用できる。
・public
公開。publicで定義されたメソッド/フィールドは、どこからでも使用できる。
なお、オーバーライドには元のメソッドから公開範囲を狭めてはいけないというルールがあります。
以下のコードを見てください。
class Super {
protected void exec() {
System.out.println("Super.exec");
}
}
class Sub extends Super {
void exec() {
System.out.println("Sub.exec");
}
}
public class Main {
public static void main(String[] args) {
Super c = new Sub();
c.exec();
}
}
このコードでは、Superクラスでprotectedによって定義されたexecメソッドをSubクラスでオーバーライドしています。
しかしその際アクセス修飾子を省略しているため、protectedより公開範囲が狭くなっているのでコンパイルエラーとなります。
この手のひっかけ問題も必ずと言ってよいほど出題されますのでしっかりと抑えておきましょう。
■継承とコンストラクタ
サブクラスのインスタンスを生成した際は、必ずスーパークラスのインスタンスから生成されるという性質があります。
以下のコードを見てください。
class A {
A() {
System.out.println("A.new");
}
}
class B extends A {}
class C extends B {
C() {
System.out.println("C.new");
}
}
public class Main {
public static void main(String[] args) {
A a = new C();
}
}
このコードの実行結果は
A.new
C.new
と出力されます。
このようにサブクラスはスーパークラスがいくつあっても、必ず一番上位のスーパークラスへ遡ってインスタンスの生成を順番に行います。
また、あえてクラスBのコンストラクタを省略していますが、省略した際もデフォルトのコンストラクタがコンパイラによって生成され、スーパークラスのコンストラクタが呼び出されます。
では以下のコードではどうでしょう。
class A {
A(String name) {
System.out.println("A.new name:" + name);
}
}
class B extends A {}
class C extends B {
C() {
System.out.println("C.new");
}
}
public class Main {
public static void main(String[] args) {
A a = new C();
}
}
このコードではクラスAに引数付きのコンストラクタが定義されています。
この場合コンパイラはデフォルトコンストラクタを生成してくれないので、クラスAのインスタンスが生成できません。
つまりコンパイルエラーになります。これを解消するにはクラスAに引数なしのコンストラクタを定義するか、クラスBを以下のように修正します。
class B extends A {
B() {
super("Test");
}
}
super()メソッドは親クラスのコンストラクタを呼び出すメソッドです。
引数は実際に定義されたコンストラクタにあわせて呼び出してやればOKです。
■まとめ
Java Silverにおいてクラスの継承について頻出されるケース、また間違えやすい部分についてはこんなところだと思います。
実際の試験問題となると難しく見えて焦ってしまうかもしれませんが、根本のところを理解し落ち着いて挑めば難しいことは言ってない(と思う)ので頑張ってください!
次回はポリモーフィズム(予定)について解説していきます。