public class Food { private String name; Food(String f) { name = f; } public static void main(String args[]) { Person p = new Person(); Vegetarian v = new Vegetarian(); Vegetable v1 = new Vegetable("Cabbage"); Food f1 = new Food("Meat"); System.out.println( "Can a person eat cabbages? "+p.Eat(v1)); System.out.println( "Can a person eat meats? "+p.Eat(f1)); System.out.println( "Can a vegetarian eat cabbages? "+ v.Eat(v1)); System.out.println( "Can a vegetarian eat meats? "+v.Eat(f1)); } } class Vegetable extends Food { String name; Vegetable(String s) { super(s); name = s; } } class Person { public boolean Eat(Food f) { return true; } } class Vegetarian extends Person { public boolean Eat(Vegetable v){return true;} }
Can a person eat cabbages? true Can a person eat meats? true Can a vegetarian eat cabbages? true Can a vegetarian eat meats? trueこのように「菜食主義者」(vegetarian) が,「肉を食べることが出来てしま う」(最後の行) が問題である.この原因として,「菜食主義者」は,「人間」の サブクラスであるので, Eat(Vegetable v) に当てはまらない場合は, 人間の Eat(Food f) を継承してしまうためである. そもそも,「菜食主義者」は,「人間」のほとんどの性質を継承するが, 「野菜以外の食べ物は食べない」ことを表現するために,オーバーライドを利 用するが,うまく表現できない.
では,例えば,
class Vegetarian { public boolean Eat(Vegetable v){return true;} }
一般に,このような時は(Java では書けないが), TypeOperator を使う ことが知られている.結果として,人間と菜食主義者のサブタイプ関係は成り 立つ.
TypeOperator Person[F<:Food] { public boolean Eat(F f) { return false; } }
TypeOperator Vegetarian[V<:Vegetable] { public boolean Eat(V v) { return ture; } }
結果として であるが,逆は成立しない関係である.ここで,クラス , のインスタン スを , とし,更に,その型を , と書く. の型が の型のサブタイプである時 とする.