本日の課題

Download Report

Transcript 本日の課題

オブジェクト指向プログラミング
11回目:継承
情報メディア学科
濱本和彦
本日の内容
継承








クラスの継承関係
継承と変数
メソッドのオーバーライド
継承とコンストラクタ
クラスの修飾子
変数の修飾子
コンストラクタの修飾子
メソッドの修飾子
ポリモーフィズム
オブジェクト指向プログラミング
三大要素のまとめ(復習の復習)
クラス



複数の関数とグローバル変数をまとめてソフトウェアを作るための
部品を作る
クラス外からのデータアクセスを許可しない
プログラムの再利用,保守
継承



重複するクラス定義を共通化する
クラスの共通部分を別クラスにまとめる仕組み
プログラムの再利用,開発の効率化
ポリモーフィズム


メソッドを呼び出す側を共通化する(同じ命令で異なる関数を実行)
開発の効率化
オブジェクト指向プログラミング
特長その2(復習の復習)
スーパークラス
変数+メソッド
継承する
サブクラスA
継承する
サブクラスB
スーパークラスの
変数+メソッド
スーパークラスの
変数+メソッド
サブクラスA固有の
変数+メソッド
サブクラスB固有の
変数+メソッド
※「継承する」と宣言するだけで,スーパークラスの変数とメソッド
をすべて定義したことになる
継承関係を作るには?
ClassA
int a; int b; double c;
ClassA{
int a; int b; double c:
}
ClassB
ClassB extends ClassA {
int d;
int a; int b; double c;
int d;
}
クラスの継承関係
Example54.javaをコンパイルし,エラーが出ないことを確
認して下さい。
←クラスParentを作成します。
class Parent {
}
class Child extends Parent { ←クラスChildを作成します。
Parentクラスを継承します。
}
class Example54{
public static void main(String args[])
{
Parent p; ←Parentクラスのオブジェクトを
参照する変数pを作成します。
p = new Parent(); ←変数pにParentクラスのオブジェクト
を割り当てます。
p = new Child();
}
}
↑変数pは,Parentクラスのオブジェクトだけでなく, そ
れを継承したChildクラスのオブジェクトも参照できます。
継承と変数
サブクラスには,スーパークラスで定義された変
数,メソッドが継承されます(コピーされます)。
サブクラス内の変数が,スーパークラスの変数と
同じ名前の場合,スーパークラスの変数は隠さ
れます。
隠されたスーパークラスの変数を参照したいとき
は,superキーワードを使います。
Example55.javaで確認して下さい。
メソッドのオーバーライド
サブクラスで宣言したメソッドと同じシグネ
チャ(メソッド名と引数のデータ型のリスト)
を持つメソッドが,スーパークラスで宣言さ
れている場合,スーパークラスのメソッドは
サブクラスオブジェクトから隠されます。
これを「メソッドのオーバーライド」と言いま
す。
Example56.javaで確認して下さい。
メソッドのオーバーライド
オーバーライドとオーバーロード

Example57.javaからはどんな値が出力され
るか予想しなさい。実行して結果を確認しまし
ょう。
Example57.java
classA
classA obj = new classC( );
void hello();
void hello(int i);
obj.hello( );
クラスclassAからオブジェクトへ
の参照objを作成する。
classB
void hello();
void hello(int i);
←ClassBで宣言されたものが優先
objの実体はクラスclassCのオブ
ジェクトとなる。
←ClassAで宣言されたものを継承
objの実体はクラスclassCのオブ
ジェクトであるため,hello()は
classCのhello()が実行される。
classC
void hello();
void hello(int i);
void hello(String s);
←ClassBで宣言されたものを継承
←ClassAで宣言されたものを継承
←ClassCで新たに宣言
よって,classBで宣言された
hello()が実行される。
メソッドのオーバーライド
スーパークラスのメソッドの参照
スーパークラスのメソッドを参照するには,
superキーワードを使います。
 Example58.javaの出力を確認し,何故そのよ
うになるのか理解しましょう。

継承とコンストラクタ
サブクラスのオブジェクトを作る時には,ス
ーパークラスのコンストラクタも実行する必
要があります。
スーパークラスのコンストラクタは,サブク
ラスのコンストラクタよりも先に実行する必
要があります。
継承とコンストラクタ
スーパークラスのコンストラクタに引数がない場合


自動的にスーパークラスのコンストラクタが先に実行され
ます。
Example59.javaでコンストラクタが実行される順番を確認
して下さい。
Example59.java
class classA{
int a;
classA() {
System.out.println("classA constructor");
a = 1;
}
}
class classB extends classA{
int b;
classB() {
System.out.println("classB constructor");
b = 2;
}
}
class classC extends classB{
int c;
classC() {
System.out.println("classC constructor");
c = 3;
}
}
class Example59{
public static void main(String args[]){
classC classc = new classC();
System.out.println("classc.a= " + classc.a);
System.out.println("classc.b= " + classc.b);
System.out.println("classc.c= " + classc.c);
}
}
classBがclassAを継承してい
るので,classAのコンストラク
タが最も先に実行されます
classCがclassBを継承してい
るので,classBのコンストラク
タが先に実行されます・・・
コンストラクタclassC()が呼
び出されますが・・・
実行結果
classA constructor
classB constructor
classC constructor
classc a=1
classc b=2
classc c=3
継承とコンストラクタ
スーパークラスのコンストラクタに引数がある場合



super(引数)を使ってスーパークラスのコンストラクタを呼
び出します。
サブクラスのコンストラクタの最初の文でなければなりま
せん。
Example60.javaで確認して下さい。
クラスの修飾子
abstract(抽象クラス)



インスタンス化できないクラス
サブクラスで実装される機能を宣言するために使われる
ポリモーフィズムを実現する
final



拡張できないクラス
メソッドをオーバーライドできないようにする
Mathクラスなど
public


他のクラスから参照できるクラス
この指定がない場合は現在のパッケージからしか参照できない
abstractの使い方
Example61.java
class Example61{
abstract class Shape{
void display() { メソッドの中身(実体)は public static void main(String args[]) {
Shape s = new Circle();
}
ここでは宣言しません
s.display();
}
s = new Rectangle();
class Circle extends Shape{
s.display();
void display() {
}
System.out.println("Circle");
Shapeクラスの参照sは,それを継承し
}
}
たクラスのオブジェクトとして実体化
}
(インスタンス化)されます。
継承クラスごとに機能が異なるメソッド
class Rectangle extends Shape{
が実装されます
void display() {
System.out.println("Rectangle");
Shapeクラスを継承したクラスの中で
}
メソッドの実体を宣言します
}
ポリモーフィズムを実現する仕組みについては「メソッドの修飾子」で説明します
変数の修飾子
final

定数として使える変数
private

同じクラスのコードからしかアクセスできない変数
protected

サブクラスまたは同じパッケージ内のコードからしかアクセスでき
ない変数
public

ほかのクラスからアクセスできる変数
static

インスタンス変数ではない変数
※ public, protected, private の3つのキーワードからは1つしか指定できません
finalの使い方
Example62.java
Example62.javaを確認して下さい。
変数xがfinalで宣言されています。
xの値を変更しようとするとどうなるか確認
して下さい。
コンストラクタの修飾子
private

同じクラスのコードからしかアクセスできないコ
ンストラクタ
protected

サブクラスまたは同じパッケージ内のコードか
らしかアクセスできないコンストラクタ
public

ほかのクラスからアクセスできるコンストラクタ
※ これら3つの修飾子は,他の修飾子と同時に指定できません。
※ 無指定の場合は同じパッケージ内のコードからしかアクセスできません。
コンストラクタの修飾子
Example63.javaの動作を確認して下さい。
コンストラクタPerson( )にprivate修飾子を付けた場合の
動作を確認して下さい。

「コンストラクタPerson( )にアクセスできない」というコンパイルエ
ラーが出ます。
Person.javaの動作を確認して下さい。




mainメソッドをPersonクラス内に含めました。
コンパイルエラーは出ずに実行可能です。
private修飾子は,同じクラス内からのアクセスのみを許可するた
め実行可能となります。
インスタンス変数を初期化しないコンストラクタ(領域だけ確保す
るもの)はクラス外から実行できないためprivate指定となります。
メソッドの修飾子
abstract


このクラスでは実装しない空のメソッド
クラス自体もabstractでなければなりません
final

オーバーライドできないメソッド
private

同じクラス内のコードからしか呼び出されないメソッド
protected

サブクラスまたは同じパッケージ内のコードからしかアクセスできないメ
ソッド
public

ほかのクラスからアクセスできるメソッド
static

インスタンスメソッドではないメソッド
※ public, protected, private は,他の修飾子と同時に指定できません。
メソッドの修飾子
Example64.java
クラスもabstract
となります。
class Example64{
abstract class Vehicle{
public static void main(String args[]){
abstract int numWheels();
Car car = new Car();
抽象メソッドの宣言
}
Truck track = new Truck();
class Car extends Vehicle{ { }は付けません。
System.out.println(car.numWheels());
int numWheels(){
System.out.println(truck.numWheels());
return 4;
} 「乗り物」クラスを用意し,その中にタイヤの数を
Vehicleクラスを継承した
}
Carクラス内で実装します。 }
確認するメソッドを用意します。これらは「抽象ク
}
ラス」「抽象メソッド」であり実体はありません。
class Truck extends Vehicle{
「乗り物」クラスを継承した「車」クラス内で,タイヤ
int numWheels(){
の数を4つと指定(=メソッドを実装)します。同様
return 6;
に「トラック」クラスでタイヤの数を6つと指定します。
Vehicleクラスを継承した
}
Trackクラス内で実装します。
「車」「トラック」それぞれのオブジェクトがもつメソッド
}
を実行してタイヤの数を出力します。
ポリモーフィズム
「ポリモーフィズム」とは,メソッドを呼び出す側の処理を
一つにまとめてしまう仕組みです。
呼び出される側が増えても,それぞれについての「呼び
出し方」を覚える必要がありません。
Example64.javaでは,車のタイヤの数を知る時は,車オ
ブジェクトに対してnumWheelメソッドを呼び出し,トラック
のタイヤの数を知る時は,トラックオブジェクトに対して
numWheelを呼び出し,実行しました。
numWheelだけ知っていれば,乗り物の種類(=呼び出
される側)が増えてもOK,という仕組みになっています。
Example65.javaは,これを応用したものです。
ポリモーフィズム
Example65.java
class Owner{
void getNumWheels(Vehicle vehicle){
System.out.println(vehicle.numWheels());
}
}
抽象クラスVehicle,抽象メソッドnumWheels()
を対象とした,呼び出し側のクラスOwnerを作成。
メソッドgetNumWheels( )は,抽象クラスVehicle
を継承したクラスのオブジェクトを引数とすること
ができる。
class Example65{
そのオブジェクトが実装している抽象メソッド
public static void main(String args[]){
numWheels( )を実行する。
Owner owner = new Owner();
Car car = new Car();
呼び出し側が,Vehicleクラスを継承したCarクラスのオブジェ
Truck truck = new Truck();
クトcarを引数としてメソッドgetNumWheels( )を呼び出すと,
owner.getNumWheels(car);
carが実装するメソッドnumWheels( )が実行される。
owner.getNumWheels(truck);
呼び出し側が,引数をTruckクラスのオブジェクトtruckに変えて
}
メソッドgetNumWheels( )を呼び出すと,自動的にtruckが実装
}
するメソッドnumWheels( )が実行される。
呼び出す側は,getNumWheelsだけ意識して,そこに抽象クラスを継承してインスタンス化されたオブジェクトを与えれば良い。
演習
Example65.javaに,Vehicleクラスを継承
するBikeクラスを作成し,numWheels()メ
ソッドを実装して下さい。ownerオブジェクト
からそのメソッドを呼び出して下さい。
3回目の授業で「ポリモーフィズム」を説明
するためにtest_pm.cppというC++のプロ
グラムを利用しました。これをJavaで書き
直してみましょう。