Instructor: Stefan Mitsch
How do we support code sharing between classes?
What should happen when methods have the same name?
toString
x
Animal
Bird
Cat
class Animal { public String toString () { return "Animal"; } }class Bird extends Animal { public String toString () { return "Bird"; } }class Cat extends Animal { public String toString () { return "Cat"; } }Animal[] xs = { new Bird(), new Cat () };for (Animal x : xs) System.out.println (x.toString());
$ javac AnimalTest.java && java AnimalTestBirdCat
class Animal { public: string to_string() { return "Animal"; } };class Bird: public Animal { public: string to_string() { return "Bird"; } };class Cat: public Animal { public: string to_string() { return "Cat"; } };Animal *xs[] = { new Bird(), new Cat() };for (Animal *x : xs) cout << x->to_string() << endl;
$ g++ -std=c++11 -o animal1 animal1.cpp && ./animal1AnimalAnimal
virtual
class Animal { public: virtual string to_string() { return "Animal";class Bird: public Animal { public: virtual string to_string() { return "Bird"; }class Cat: public Animal { public: virtual string to_string() { return "Cat"; } Animal *xs[] = { new Bird(), new Cat() };for (Animal *x : xs) cout << x->to_string() << endl;
$ g++ -std=c++11 -o animal2 animal2.cpp && ./animal2BirdCat
class Animal { public: virtual string to_string() { return "Animal";class Bird: public Animal { public: virtual string to_string() { return "Bird"; }class Cat: public Animal { public: virtual string to_string() { return "Cat"; } Animal xs[] = { Bird(), Cat() };for (Animal x : xs) cout << x.to_string() << endl;
$ g++ -std=c++11 -o animal3 animal3.cpp && ./animal3AnimalAnimal
interface Fn { int apply (int x); }class F implements Fn { public int apply (int x) { return x + 1; } }class G implements Fn { public int apply (int x) { return x + 2; } }class H implements Fn { public int apply (int x) { return x + 3; } }
Fn[] fs = { new F (), new G (), new H () };for (int i = 0; i < fs.length; i++) { System.out.format ("fs[%d].apply(20)=%d\n", i, fs[i].apply(20));}
fs[0].apply(20)=21fs[1].apply(20)=22fs[2].apply(20)=23
interface Fn { int apply (int x); }
Fn[] fs = new Fn[3];for (int i = 0; i < fs.length; i++) { int j = i + 1; // effectively final fs[i] = new Fn() { int apply (int x) { return j + x; } }}for (int i = 0; i < fs.length; i++) { System.out.format ("fs[%d].apply(20)=%d\n", i, fs[i].apply(20));}
Fn[] fs = new Fn[3];for (int i = 0; i < fs.length; i++) { int j = i + 1; // effectively final fs[i] = x -> x + j; }for (int i = 0; i < fs.length; i++) { System.out.format ("fs[%d].apply(20)=%d\n", i, fs[i].apply(20));}
this
A
class A { int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}
f
A x = new A ();x.f (2);
A.f (2)A.f (1)A.f (0)A.g ()$1 ==> 0
B
g
class A { int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}class B extends A { int g () { System.out.println ("B.g ()"); return 0; }}
A x = new B ();x.f (2);
A.f (2)A.f (1)A.f (0)B.g ()$1 ==> 0
abstract class A { int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}class B extends A { int g () { System.out.println ("B.g ()"); return 0; }}
A x = new A ();
| Error:| A is abstract; cannot be instantiated| A x = new A ();| ^------^
abstract class A { int f (int x) { // ... } abstract int g ();}class B extends A { }
| Error:| B is not abstract and does not override abstract method g() in A| class B extends A {| ^------------------...
abstract class A { final int f (int x) { // ... } abstract int g ();}class B extends A { int f (int x) { System.out.format ("B.f (%d)%n", x); return 0; } int g () { System.out.println ("B.g ()"); return 0; } }
Compile error
| Error:| f(int) in B cannot override f(int) in A| overridden method is final| int f (int x) { System.out.format ("B.f (%d)%n", x); return 0; }| ^--------------------------------------------------------------^
abstract class A { int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); } abstract int g ();}class B extends A { int f (int x) { System.out.format ("B.f (%d)%n", x); return 0; } int g () { System.out.println ("B.g ()"); return 0; } }
A x = new B (); x.f (2);
B.f (2)$1 ==> 0
class A { int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}class B extends A { int f (int x) { System.out.format ("B.f (%d)%n", x); return 0; } int g () { System.out.println ("B.g ()"); return 0; } }
A.f
class A { int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}class B extends A { int f (int x) { System.out.format ("B.f (%d)%n", x); return this.f(x); } int g () { System.out.println ("B.g ()"); return 0; } }
B.f (2)B.f (2)B.f (2)B.f (2)... // infinite loop
super
class A { int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}class B extends A { int f (int x) { System.out.format ("B.f (%d)%n", x); return super.f(x); } int g () { System.out.println ("B.g ()"); return 0; } }
B.f (2) A.f (0) A.f (2) B.g () B.f (1) $1 ==> 0A.f (1)B.f (0)
class A { B that; int f (int x) { System.out.format ("A.f (%d)%n", x); return (x == 0) ? this.g () : this.f (x - 1); // return (x == 0) ? that.g () : that.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}class B { A that; int f (int x) { System.out.format ("B.f (%d)%n", x); return that.f (x); } int g () { System.out.println ("B.g ()"); return 0; }}
A x = new A ();B y = new B ();x.that = y;y.that = x;y.f (2);
B.f (2) A.f (2)A.f (1)A.f (0)A.g ()$1 ==> 0
class A { B that; int f (int x) { System.out.format ("A.f (%d)%n", x); // return (x == 0) ? this.g () : this.f (x - 1); return (x == 0) ? that.g () : that.f (x - 1); } int g () { System.out.println ("A.g ()"); return 0; }}class B { A that; int f (int x) { System.out.format ("B.f (%d)%n", x); return that.f (x); } int g () { System.out.println ("B.g ()"); return 0; }}
B.f (2) A.f (2)B.f (1)A.f (1)B.f (0)A.f (0)B.g ()$1 ==> 0
var A = { f (x) { console.log ("A.f (" + x + ")") return (x == 0) ? this.g () : this.f (x - 1); }, g () { console.log ("A.g ()"); return 0; }}var B = { f (x) { console.log ("B.f (" + x + ")"); return super.f (x); }, g () { console.log ("B.g ()"); return 0; }}
Object.setPrototypeOf(B, A);B.f (2);