3. 演習[1]
class Dog { (A)どのような出力が得られるか?
public static void bark() { (B) bark()メソッドがstatic宣言されて
System.out.print("woof");
} いない場合の出力は?
} (C)メソッドがどのように実行されて
class Bulldog extends Dog { いるか説明せよ
public static void bark() {}
}
public class Bark {
public static void main(String args[]) {
Dog d1 = new Dog();
Dog d2 = new Bulldog();
d1.bark();
d2.bark();
}
} ヒント
Java言語仕様 §15.12 Method Invocation Expressions
3
5. コンパイラおよびVMによる処理
(2) コンパイル時のチェック
class Dog {
Dogのメソッドbark()は
public static void bark() {
System.out.print("woof"); static宣言されている
}
}
(3) 実行時処理
class Bulldog extends Dog { Dogのstaticメソッド
public static void bark() {} bark()を呼び出そう!
}
public class Bark {
public static void main(String args[]) {
Dog d1 = new Dog();
Dog d2 = new Bulldog();
d1.bark();
d2.bark(); (1) コンパイル時のチェック
} - d1,d2どちらもDog型の変数
} - Dogのメソッドbark()があるのでOK
5
6. コンパイラおよびVMによる処理(staticメソッドでない場合)
(2) コンパイル時のチェック
class Dog {
Dogのメソッドbark()は
public void bark() {
System.out.print("woof"); virtual呼び出しだ
}
}
(3) 実行時処理
class Bulldog extends Dog { d1,d2が参照している
public void bark() {} インスタンスをチェック!
}
public class Bark { (4) 実行時処理
public static void main(String args[]) {
それぞれのインスタンスから って
Dog d1 = new Dog(); メソッドを呼び出そう!
Dog d2 = new Bulldog();
d1.bark();
d2.bark(); (1) コンパイル時のチェック
} - d1,d2どちらもDog型の変数
} - Dogのメソッドbark()があるのでOK
6
15. 演習[3]
class Purse {
private int i;
public Purse(int arg) {
i = arg;
}
public int get_i() { return i; }
public void set_i(int iarg) { i = iarg; }
}
class User {
private Purse p;
(A) User クラスのインスタンスを生成し,
public User(Purse arg) {
p = arg; その private フィールド p が参照する
} Purse インスタンスの持つ値を変更す
public Purse get_p() {
return p; る攻撃コードを書け.
} (B) (A) でつくった攻撃コードが動作しな
}
いように元のコードを修正せよ.
15
16. 攻撃コード例
こんなことすると......
class dc {
public static void main(String[] args){
Purse newp = new Purse(9999);
User u = new User(newp);
System.out.println(u.get_p().get_i());
get_p() の返り値を使って u
Purse p = u.get_p();
の private フィールドをいじる
p.set_i(1099);
System.out.println(u.get_p().get_i()); ことができる
newp.set_i(999);
System.out.println(u.get_p().get_i());
}
}
コンストラクタに渡したオブジェクトを使って u の
private フィールドをいじることができる
16
17. 修正例
class User {
private Purse p;
受け取ったオブジェクトはコ
public User(Purse arg) {
p = new Purse(arg.get_i()); ピーを作って使う.
}
public Purse get_p() {
return new Purse(p.get_i());
} 外に渡すオブジェクトはコ
} ピーを作って使う.
defensive copy : デフェンシブコピー
17
18. 修正例(2) Purseクラスを公開する必要がなければ...
class User { Purse クラスを入れ子クラスと
して定義する. Purse の中身へ
private class Purse {
のアクセスは必ず User クラス
private int i;
Purse(int arg) { i = arg; } のメソッド経由とする.
int get_i() { return i; }
void set_i(int iarg) { i = iarg; }
}
private Purse p;
public User(int iarg) {
p = new Purse(iarg);
}
public int get_i() { return p.get_i(); }
public void set_i(int i) { p.set_i(i); }
}
18