Instructor: James Riely
x
has static type Animal
, dynamic type 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 AnimalTest
Bird
Cat
x
has static type Animal
, dynamic type Bird
/Cat
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 && ./animal1
Animal
Animal
x
has static type Animal
, dynamic type Bird
/Cat
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 && ./animal2
Bird
Cat
virtual
methods
x
has static type Animal
, dynamic type Animal
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 && ./animal3
Animal
Animal
truncatesthe object, coercing to parent class
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)=21
fs[1].apply(20)=22
fs[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));
}
fs[0].apply(20)=21
fs[1].apply(20)=22
fs[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] = 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));
}
fs[0].apply(20)=21
fs[1].apply(20)=22
fs[2].apply(20)=23
this
has static type A
, dynamic type 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; }
}
A x = new A ();
x.f (2);
A.f (2)
A.f (1)
A.f (0)
A.g ()
$1 ==> 0
this
has static type A
, dynamic type B
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) {
System.out.format ("A.f (%d)%n", x);
return (x == 0) ? this.g () : this.f (x - 1);
}
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) {
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; }
}
//
| 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 x = new B ();
x.f (2);
B.f (2)
$1 ==> 0
//
A.f
with this
?
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; }
}
A x = new B ();
x.f (2);
B.f (2)
B.f (2)
B.f (2)
B.f (2)
... // infinite loop
A.f
with 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; }
}
A x = new B ();
x.f (2);
B.f (2) A.f (0)
A.f (2) B.g ()
B.f (1) $1 ==> 0
A.f (1)
B.f (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 { A that = new A ();
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 x = new B ();
x.f (2);
B.f (2) $1 ==> 0
A.f (2)
A.f (1)
A.f (0)
A.g ()
interface I { int f (int x); int g (); }
class A implements I { I back = this; public
int f (int x) {
System.out.format ("A.f (%d)%n", x);
return (x == 0) ? back.g () : back.f (x - 1);
} public
int g () { System.out.println ("A.g ()"); return 0; }
}
class B implements I { A a; B () { a = new A (); a.back = this; } public
int f (int x) { System.out.format ("B.f (%d)%n", x);return a.f (x);}public
int g () { System.out.println ("B.g ()"); return 0; }
}
B x = new B ();
x.f (2);
B.f (2) A.f (0)
A.f (2) B.g ()
B.f (1) $1 ==> 0
A.f (1)
B.f (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);
B.f (2) A.f (0)
A.f (2) B.g ()
B.f (1) $1 ==> 0
A.f (1)
B.f (0)
java.io.InputStream
represents stream of bytes
read()
in subclass
public abstract class InputStream implements Closeable {
public abstract int read() throws IOException;
public int read (byte b[], int off, int len) throws IOException {
... // calls read()
}
public long skip(long n) throws IOException {
... // calls read(byte b[], int off, int len)
}
...
}
java.io.InputStream
API docs
InputStream
must always provide a method that returns
the next byte of input.
read(b,
off,
len)
method for class InputStream
simply
calls the method read()
repeatedly.
skip(n)
method of this class creates a byte array and then repeatedly reads into it until
n
bytes have been read or the end of the stream has been reached.
public class DemoStream extends InputStream {
int next = 0;
public int read () throws IOException {
int result = 32 + next;
next = (next + 1) % (127 - 32);
return result;
}
public static void main (String[] args) {
byte[] buffer = new byte[50];
InputStream is = new DemoStream ();
for (int i = 0; i < 3; i++) {
try { int numread = is.read (buffer, 0, buffer.length);
System.out.println (new String (buffer, 0, numread));
} catch (IOException e) {}
} } }
$ javac DemoStream.java && java DemoStream
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQ
RSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$
%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUV