アルゴリズムとプログラミング

アルゴリズムとプログラミング
(Algorithms and Programming)
第10回:インスタンス変数、クラス変数
•インスタンス変数とクラス変数
•インスタンスメソッドとクラスメソッド
•ローカル変数とスコープ
•変数の寿命、ガーベージコレクション
講義資料等: http://www.pe.titech.ac.jp/~watanabe/lecture/ap/index-j.html
インスタンス変数
class Point { // 点クラス
double x; // x座標
double y; // y座標
}
Point p1 = new Point();
Point p2 = new Point();
p1とp2はクラスは同じだが、
別のインスタンスであり、それ
ぞれ個別に変数double x,
double yを持つ
これまで出てきた変数は、
インスタンスごとにメモリ領
域が個別に割り当てられ、
別々に読み書きができた
インスタンス変数
Point: p1
Point: p2
x: 1.5
y: 2.0
x: 0.2
y: 0.0
お互い無関係に
読み書き可能
クラス変数
同じクラスのどのインスタンスからでも、共
通の1つの変数(=メモリ領域)を読み書き
したい場合がある
p1からクラス変数の値を
変更すると、p2から見ても
値が変更されている!!
クラス変数
実体は1つ
Point: p1
Point: p2
x: 1.5
y: 2.0
count :
x: 0.2
y: 0.0
count :
count : 2.0
クラス変数
クラス全体で
共有する変数
クラス変数の宣言
class Point { // 点クラス
double x; // x座標
double y; // y座標
public static int count;
}
static修飾子
クラス変数へのアクセス方法:
オブジェクト変数名.クラス変数名
クラス名.クラス変数名
クラス変数の宣言と利用の例
class Point { // 点クラス
double x; // x座標
double y; // y座標
//クラス変数の定義と初期化(static修飾子の有無で出力結果を比較せよ)
public static int count = 0;
Point( double a, double b ){ コンストラクタ
x = a; y = b;
count++;
}
}
class SampleAP0801 {
public static void main(String[] args){
// インスタンスが生成される前からクラス変数は存在する!
System.out.println("count=" + Point.count);
count=0
Point p1 = new Point(1.0,2.0);
System.out.println("count=" + p1.count);
Point p2 = new Point(3.0,4.0);
count=1
System.out.println("count=" + p2.count);
count=2
}
}
クラスメソッド
クラス単位で共有されるメソッド
インスタンス変数にアクセス不可
インスタンスメソッドの呼び出し不可
クラスメソッドは、クラス内で定義されてい
るのでクラスのメンバーといえるが、実体
はインスタンスの外に存在する
オブジェクト(実体)
インスタンス1
インスタンス変数
インスタンスメソッド
クラス変数
クラスメソッド
クラス定義
インスタンス2
static
static
インスタンス3
クラスで共有
static
static
アクセス
class Point { // 点クラス
double x; // x座標
インスタンス変数
double y; // y座標
//クラス変数、クラスメソッドの定義
クラス変数 public static int count = 0;
クラスメソッド public static void printValue(){
System.out.println( "value:" + count );
}
クラスメソッド public static void printValue(int i){
System.out.println( "value:" + i );
}
クラスメソッドの中からインスタンス変数で
}
あるx,yを参照することはできない!
class SampleAP0802 {
public static void main(String[] args){
// インスタンスが生成される前からクラス変数、クラスメソッドは存在する!
Point.count = 5 ;
value:5
Point.printValue();
Point.printValue(6);
value:6
Point o = new Point();
o.printValue(7);
value:7
}
}
main()はクラスメソッドだった!
class ユーザ定義 {
public static void main(String[] args){
処理;
}
}
main()メソッドが実行される約束
になっている
どこで宣言された変数か?
変数の3つの分類
宣言される場所
•インスタンス変数
•クラス変数
•ローカル変数
クラス内
メソッド内
ローカル変数が見える
範囲(スコープ)と寿命
中カッコ{}で囲まれたブロックがスコープの目印
class SampleAP0803 {
public static void main(String[] args){
int x = 0;
for( int i = 1; i <= 10; i++) {
x = x + i;
}
System.out.println("total = " + x );
}
}
変数iの値をこのforブロックの外から参照することはできない
変数xの値はforブロック内からでも参照可能
変数の寿命
使い終わった変数は破棄され、使用
していたメモリが解放される
(ガベージコレクション)
ローカル変数の寿命:ブロックの最初にメモリが確保さ
れ、ブロックの終わりで破棄される
インスタンス変数の寿命:newで生成されてから、
最後に参照された後、Java VM が判断したタイミ
ング
クラス変数の寿命:プログラムの開始から終了まで
バッティングしても有効
ローカル変数
SampleAP0804.java
class X {
static int i = 100; クラス変数
int j = 200; インスタンス変数
void printValue(){
System.out.println("i=
System.out.println("j=
int i = 123;
ローカル変数
int j = 456;
System.out.println("i=
System.out.println("j=
}
}
" + i );
" + j );
" + i );
" + j );
SampleAP0804.java続き
class SampleAP0804 {
public static void main(String[] args){
X o = new X();
o.printValue();
}
}
実行結果
i=
j=
i=
j=
100
200
123
456
ローカル変数
クラス変数・インスタンス変数
変数名がバッティングした場合は
ローカル変数が優先される
バッティングしないように名前を付けるのが望ましい
値を変更しない変数(定数)の宣言
final修飾子
class X {
static final int MAX = 100;
final static int MIN = -100;
final int DEFAULT = 10; 値を変更しないのなら、インスタンスご
とにこの定数のためにメモリを確保す
}
るのは無駄といえる→普通はクラス変
数にする(static)
class SampleAP0805 {
public static void main(String[] args){
System.out.println("value= " + X.MAX);
System.out.println("value= " + X.MIN);
X o = new X();
System.out.println(
"value= " + o.DEFAULT);
}
}
まとめ
•インスタンス変数とクラス変数
•インスタンスメソッドとクラスメソッド
•ローカル変数とスコープ
•変数の寿命、ガーベージコレクション
•final修飾子
アルゴリズムとプログラミング
(Algorithms and Programming)
第11回:継承の実装
•継承の実装: extends キーワード
コンストラクタ
•継承とメソッドのオーバーライド,可視性
•抽象クラス (abstractキーワード)
講義資料等: http://www.pe.titech.ac.jp/~watanabe/lecture/ap/index-j.html
スーパークラス
継承の実装
Vehicle(乗り物)
- speed: double
# changeSpeed(s:double)
# getSpeed(): double
サブクラス
Plane
- altitude: double
# takeOff ()
# land ()
サブクラスは、スーパークラス
の全てのフィールドとメソッドを
含んでいる。
(実際にアクセスできるかは、
アクセス修飾子に従う)
継承の実装:extendsキーワード
スーパークラス
Vehicle(乗り物)
- speed: double
# changeSpeed(s:double)
# getSpeed(): double
サブクラス
Plane
- altitude: double
# takeOff ()
# land ()
class Plane extends Vehicle {
private double altitude;
protected void takeOff() {
処理(スーパークラスのメソッドも呼べる);
}
protected void land() {
処理;
}
}
スーパークラスへのアクセス
スーパークラス
Vehicle(乗り物)
- speed: double
# changeSpeed(s:double)
# getSpeed(): double
サブクラス
Plane
- altitude: double
# takeOff ()
# land ()
public static void main(略) {
Plane o = new Plane();
o.changeSpeed(0.0);
for(int i=0;i<=300;i+=50){
o.changeSpeed(i);
o.takeOff();
}
System.out.println("離陸!");
}
}
全てのクラスのスーパークラス
Objectクラス
extendsキーワードが
無い全てのクラスは、自
動的にObjectクラスの
サブクラスとなる。従って、
全てのクラスはObject
クラスのフィールドとメ
ソッドを暗黙的に継承し
ている。
Objectクラス
Vehicle(乗り物)
- speed: double
# changeSpeed(s:double)
# getSpeed(): double
Plane
- altitude: double
# takeOff ()
# land ()
継承とコンストラクタ
サブクラスのコンストラクタを呼び出すと..
1. まずスーパクラスのコンストラクタが実行される
(何も指定しなければデフォルトコンストラクタが呼ばれる.引数は無し)
2. 次にサブクラスのコンストラクタが実行される
サブクラスのコンストラクタ(例)
SampleAP0901.java
class
int
X()
x
}
}
class
int
Y()
y
}
}
X {
x;
{
= 100;
Y extends X {
y;
ここにsuper();が省略
{
= 200;
されていると考える
サンプルプログラム(続き)
SampleAP0901.java続き
class SampleAP0901 {
public static void main(String[] args) {
Y o = new Y();
System.out.println("x= " + o.x );
System.out.println("y= " + o.y );
}
}
実行結果
x= 100
y= 200
親のコンストラクタを指定する場合
Superキーワード
SampleAP0902.java
class X {
int x;
X(int a) {
x = a;
}
}
class Y extends X {
int y;
Y(int a, int b) {
super(a);
y = b;
}
}
(thisキーワードとの併用は不可)
コンストラクタでsuperを使うときは
最初の行でしか使えない!
SampleAP0902.java続き
class SampleAP0902 {
public static void main(String[] args) {
Y o = new Y( 1, 2 );
System.out.println("x= " + o.x );
System.out.println("y= " + o.y );
}
}
実行結果
x= 1
y= 2
暗黙の親コンストラクタ呼び出し
SampleAP0901.java(再)
class
int
X()
x
}
}
class
int
Y()
y
}
}
X {
x;
{
= 100;
Y extends X {
y;
ここにsuper();が省略
{
= 200;
されていると考える
継承を禁止するfinalキーワード
final class X {
int x;
サブクラスの宣言を禁止!
}
class Y extends X {
int y;
}
コンパイルエラー!
final宣言したクラスは、extendsで
サブクラスを作ることが禁止される
メソッドのオーバーライド
オーバーライド(override)
親クラスと子クラスのそれぞれに、
メソッド名、引数、戻り値が全て同一で
内容が異なるメソッドを定義すること
既出
オーバーロード (overload)
混同注
意!
ひとつのクラス内に、メソッド名が同じ
で、引数の型及び数が異なるメソッドを
定義すること
オーバーライドの目的
Vehicle(エンジン付き乗り物)
- speed: double
# getSpeed(): double
# startEngine ()
Plane
- altitude: double
# takeOff ()
# startEngine ()
もともと、サブクラスにはスー
パークラスのフィールドとメ
ソッドが全て自動的に引き継
がれている。
しかし、引き継がれているメ
ソッドの処理内容を、サブク
ラスで再定義(変更)したい場
合がある 。
オーバーライドの必要性
オーバーライドと可視性
子クラスでオーバーライドするメソッドの可視性は、
親クラスのメソッドの可視性により制限される
オーバーライドされる
スーパークラスのメソッド
に指定されている修飾子
オーバーライドするサブクラスのメソッド
public
public指定が必要
protected
protectedかpublicが必要
private
アクセス不可につき、オーバーライド不可
無指定
private指定は不可
親クラスでprotectedが指定されているメソッドを子クラスでオーバーライドするにはprotectedかpublic指定が必要
親・子クラスにおける
オブジェクト参照型変数の互換性
Javaのきまり:
型の違いに厳しいJavaですが..
•子クラスのインスタンスを指すオブジェ
クト参照型変数を、親クラスの参照変数
に代入することができる。
•代入後も、インスタンスの出身が子クラ
スであることを忘れずに記憶しておく仕
組みになっている。
1つのオブジェクトが、あたかも複数の型を持
つかのように見せることができる。
オブジェクト指向3原則:ポリモーフィズム
(メソッドのオーバーライドと参照型変数の
互換性によって実現される)
乗り物
飛行機
ジェット機
ジェット機クラスのインスタン
スを、乗り物オブジェクトとして
扱うことができる。
自動車
プロペラ機
ジェット機は飛行機でも
あり、乗り物でもある
ジェット機クラスのインスタン
スに対する操作を、乗り物に
対する操作として記述できる
このような記述の仕方に
どんなメリットがあるの?
乗り物
#動力を始動する()
飛行機
自動車
#動力を始動する()
ジェット機
#動力を始動する()
#動力を始動する()
プロペラ機
#動力を始動する()
操作名は同じだ
が、実際の操作
内容はそれぞれ
異なる
メソッドのオーバーライド
ジェット機クラスのインスタンスを生成する
:ジェット機
new ジェット機();
このインスタンスを乗り物オブジェクトと見なす
(乗り物オブジェクト変数 v1 に格納する)
乗り物 v1 = new ジェット機();
乗り物クラス
ジェット機クラスのインスタンスへの参照
動力を始動する()メッセージを送る
v1.動力を始動する()
乗り物オブジェクトの操作が呼び出
されるように記述されているが、自動
的にジェット機オブジェクトに対する
操作が呼び出される
この記法は、ジェット機に限ら
ず、プロペラ機にも自動車にも、
将来的に追加される乗り物に
もそのまま変更なく使える。
上位概念(スーパークラス)オブジェクトに対する操作と
して記述しておくと、サブクラスの細かい修正や追加な
どに対して強いプログラムになる(保守性が高い)
ジェット機クラスのインスタンスを生成する
:ジェット機
new ジェット機();
このインスタンスをジェット機オブジェクト変数 j1 に格納する
ジェット機 j1 = new ジェット機();
ジェット機クラス
ジェット機クラスのインスタンスへの参照
動力を始動する()メッセージを送る
j1.動力を始動する()
この記法では、プロペラ機や自動車に変更したり、さらに
は将来的に追加される乗り物に対しては、そのままでは
使えない。プログラムの記述を変更する必要がある!
ポリモーフィズムの意味と効果
ポリモーフィズム(polymorphism)の意味:
1つのオブジェクトが複数の型を持つ ← 継承により実現
ポリモーフィズムの活用の仕方:
上位概念(スーパークラス)への操作としてプログラ
ムを記述する
その効果:
サブクラスの細かい修正や追加などに対して強い
(保守性が高い)プログラムになる
オブジェクト指向プログラミングの有効性!
参照型変数への代入 (例)
SampleAP1001.java
class X { // スーパー(親)クラス
int x;
}
class Y extends X { // サブ(子)クラス
int y;
}
class SampleAP1001 {
public static void main(String[] args){
X o = new Y();//サブクラスYのインスタンスを親クラスX
}
//の参照型変数へ代入できる!
}
メソッドのオーバーライド(例)
SampleAP1002.java
class Shape { //2次元図形の面積を表現するクラス
double a; //一般に、面積を計算するには、縦×横や底辺×高さ/2など、
double b; //2つの辺の長さを与える必要があると考え、変数を2つ用意する
Shape(double x, double y) {
a = x;
b = y;
}
double getArea() { //ここでは具体的な定義を与えないことにする。
return 0.0;
//具体的な定義はサブクラスで与える。
}
}
SampleAP1002.java続き
class Triangle extends Shape { //三角形
Triangle(double x, double y);
super(x,y); // x,yとしては底辺と高さを与える
}
double getArea() {
オーバーライド
return ( a * b / 2 );
}
}
class Rectangle extends Shape { //四角形
Rectangle (double x, double y){
super(x,y); //x,yとしては各辺の長さを与える
}
double getArea() {
オーバーライド
return ( a * b );
}
}
SampleAP1002.java続き
class SampleAP1002 {
public static void main(String[] args) {
Shape o1 = new Shape( 10.0, 10.0 );
Shape o2 = new Triangle( 10.0, 10.0 );
Shape o3 = new Rectangle( 10.0, 10.0 );
System.out.println("o1の面積は" +
o1.getArea() );
System.out.println("o2の面積は" +
o2.getArea() );
System.out.println("o3の面積は" +
o3.getArea() );
}
}
実行結果
o1の面積は0.0
o2の面積は50.0
o3の面積は100.0
引数に与えた数値はo1~o2まで
全て同じだが、それぞれオーバー
ライドされたgetArea()メソッドが、
異なる処理を実行している。
抽象クラス: 抽象メソッドを持つためオブジェ
クト生成できないクラス
乗り物
-スピード
#スピードを変える()
#スピードを表示する()
飛行機
-高度
#離陸する()
#着陸する()
#高度を表示する()
クラス名をイタリックにすると
抽象クラス
乗り物クラスのインスタンスは
存在しないことが保証される
飛行機クラスでは、依然として
スピードを表示する()操作は必須
であり、乗り物クラスは使われる。
抽象クラスの実装
親クラスではメソッド名だけ定義して、子ク
ラスにおいて、オーバーライドにより具体的
な処理内容を記述する
抽象メソッド: abstractキーワード
具体的な処理内容が与えられていな
いため、インスタンスの作成は不可
抽象クラスの使用例
SampleAP1003.java
abstract class Shape { //抽象クラス
double a;
double b;
Shape(double x, double y) {
a = x;
b = y;
}
//抽象メソッドとして定義(この方が自然)
abstract double getArea();
}
•抽象メソッドが1つでもあるとそのクラスは抽象クラス
→サブクラスで具体的な処理内容を与えて使用する
•抽象クラスだからといって、全てが抽象クラスである必要は無い
SampleAP1003.java続き
この部分はSampleAP1002.javaと同じ
class Triangle extends Shape { //三角形
Triangle(double x, double y);
super(x,y); // x,yとしては底辺と高さを与える
}
double getArea() {
return ( a * b / 2 );
}
}
class Rectangle extends Shape { //四角形
Rectangle (double x, double y){
super(x,y); //x,yとしては各辺の長さを与える
}
double getArea() {
return ( a * b );
}
}
SampleAP1003.java続き
class SampleAP1003 {
public static void main(String[] args) {
Shape o2 = new Triangle( 10.0, 10.0 );
Shape o3 = new Rectangle( 10.0, 10.0 );
System.out.println("o2の面積は" +
o2.getArea() );
System.out.println("o3の面積は" +
o3.getArea() );
}
}
抽象クラスのインスタンス化を削除
まとめ
•継承の実装: extends キーワード
•継承とコンストラクタ: superキーワード
•継承の禁止: finalキーワード
•継承とメソッドのオーバーライド
•抽象メソッド、抽象クラス
より保守性の高いプログラムの実現
世の中で既に作成され公開されている各種のJavaクラ
スライブラリはこのような考え方で作成されている。適当
なクラスを継承してカスタマイズすることにより、極めて
簡単に自分独自の問題を解決することができる。