クラスの継承

前回のまとめ

  • 型は大別してプリミティブ型と参照型の2つ。
  • プリミティブ型は「箱」のイメージでOK。代入は「値をコピー」
  • 参照型は「商品タグ」のイメージ。インスタンスを指し示すのがインスタンス名(変数名)。代入は「商品タグが同じところに繋がる(ポインターのコピー)」
  • プリミティブ型と参照型では、代入や比較等で(初学者にとって)直感的でない違いがあるので注意する。この違いはコードを実行して確かめること。
  • 文字列や配列は参照型。よく使われるので「特別扱い」されている(使いやすくなっている)。

クラスの継承

継承のポイント

  • 継承とは、既存のクラスをもとに新しいクラスを定義する機能のこと。
  • 元となるクラスをスーパークラス(親クラス)、新しく定義するクラスをサブクラス(子クラス)という。
  • サブクラスはスーパークラスのメンバー(フィールドとメソッド)を受け継ぐ。
  • サブクラスでは新しくメンバーを加えることができる。
  • スーパークラスのメソッドをサブクラスで書き換える(動作を変える)ことができる(オーバーライド)。オーバーライドするときはアノテーションをつけたほうが良い。

  • サブクラスのインスタンスは、スーパークラスのインスタンスとして扱うことができる。
  • スーパークラスを指定していなくても(指定していない場合は)、Objectクラスがスーパークラスになる。つまり、すべてのクラスの元をたどるとObjectクラスに行き着く。
  • サブクラスからスーパークラスのメンバーを呼び出すことができるが、その場合に「super」を使う場合がある。

継承の利用例1

クラス図1

継承の利用例2

クラス図2

プリミティブ型(基本型)と参照型(クラス型)

The types of the Java programming language are divided into two categories: primitive types and reference types.

Java言語の型は次の2つのカテゴリーに分けられる: プリミティブ型と参照形。

プリミティブ型(基本型)

次の8種類。整数はすべて符号付きで、C言語と違ってunsignedはない。

格納できる値 備考
boolean 真偽値(trueもしくはfalse)
char 1文字 Unicodeのコードを表す16ビットの整数。教科書P.12
byte 整数(8ビット) 教科書P.10
short 整数(16ビット) 教科書P.10
int 整数(16ビット) 教科書P.10
long 整数(32ビット) 教科書P.10
float 実数(32ビット) 教科書P.11
double 実数(64ビット) 教科書P.11

基本型の変数は、「箱」のイメージで問題ない。変数名は箱についている名前。

では、次のコードを実行してみよう(コード全体)。

(1)では、aに0、bに1を代入している。

(1) プリミティブ型の宣言と初期化

(2)で代入という操作をすると、aの値がコピーされてbに入る。

Primitive2

(3)で、aに代入するとaの値が変わる。bの値は変わらない。

Primitive3

参照型(クラス型)

参照型はクラス型ともいい、要するに、クラスによる型のこと。クラス型の変数は、クラス(やインターフェース)の実体(インスタンス)を格納する。

例えば、円(通貨じゃなくて図形の方)を表すCircleクラスを定義して、インスタンス化することを考えよう。半径を表すフィールドを持つクラスである。

この場合の変数は、プリミティブ型の時と違って、「箱」のイメージではない!「商品タグ」のイメージが適切である。特に代入演算子を使った時の処理について注意が必要だ。実際に実行して、代入がどのような操作なのか確認しよう。

(4)では、インスタンス化して、フィールドに値を代入している。変数名(インスタンス名)は商品タグのようにインスタンスに紐づいている。

(4) 参照型のインスタンス化とフィールドへの代入

(5)で、代入の操作を行っているが、これは「c2の紐付け先をc1のものと同じにする」という意味になる(C言語がわかっている人向けの説明: ポインタのコピー)。元々c2が紐づいていたインスタンスはどこからも使われていない状態になったので、ガベージコレクタ(教科書P.92)によって、そのうちメモリから消される。

Reference2

(6) c1のフィールドの値を代入によって変更すると、c2のフィールドも同じになる(というか同じものを指し示している)。

Reference3

このように、参照型では(初学者にとっては)直感と違う処理が行われるので注意する。この辺りについては「シャローコピー」や「ディープコピー」といった単語で検索してみると理解が深まるだろう。

そして、配列は、参照型として扱われる(要素がプリミティブ型であっても)。

(7)、(8)、(9)でどのように変化するのか確認しよう。

比較

代入だけではなく、比較についても注意しなければならない。次のコードを実行して見よう(コード全体)。

参照型の比較は、「指し示しているインスタンスが同じか」という比較をしているので、フィールドの値がすべて同じであったとしても指し示しているインスタンスが違えばfalseとなる。参照型は、普通は「==」で比較してはいけない、と覚えておこう(もちろん、同じインスタンスを指し示しているか、という判別が必要なときはこれで良い)。

では、参照型で比較したい場合はどうしたらいいのだろうか?これは、地味にフィールドを比較していくしかない。Circleクラスの場合はフィールドが1つだけなので簡単だが、フィールドがたくさんある場合は大変だ。なので、比較が必要なクラスは比較するためのメソッドを作っておくのが良い。じゃあ、そのメソッドをどうやって作るか、利用するか、ということに興味があったら「java equals override」といったキーワードで調べよう。

参照型あれこれ

文字列

Javaの文字列はStringクラスのインスタンスだ。つまり参照型だ。だから、比較などでは注意しなければならない。また、文字列は非常によく使われるので、特別扱いされている。

特別扱い1: 普通のクラスはnew演算子でインスタンス化を行うが、文字列のインスタンス化はダブルクォーテーションで囲むことによってインスタンス化することができる!

ちなみに、ダブルクォーテーションを使わず、charの配列から文字列を作ると次のようになる。

特別扱い2: +演算子で結合ができる!(教科書P.13、ちなみに、「演算子のオーバーロード」という機能がある言語では、+演算子の機能を変えることができる)

Javaの文字列は様々なメソッドが用意されているので使ってみよう。