Consider the following UML diagram:
(Notice that Ball
is in italics, indicating that it is abstract.)
For example, the cell marked with red would represent the following assignment:
// Variable type: Football / Object type: Tossable Football ball = new Tossable();This cell should is marked — because it is impossible to instantiate an object of type
Tossable
.
Variable Type | ||||||
Tossable | Ball | Rock | Baseball | Football | ||
Object Type | Tossable | — | — | — | — | — |
Ball | — | — | — | — | — | |
Rock | ✓ | X | ✓ | X | X | |
Baseball | ✓ | ✓ | X | ✓ | X | |
Football | ✓ | ✓ | X | X | ✓ |
1. Ball ball = new Football("spalding"); // CE 2. Ball ball = new Football("Spalding"); Baseball baseball = (Baseball)ball; // C // This will compile, but an exception will be thrown at run-time. // A variable of type Baseball can never contain an object of type // Football. 3. Object obj = new Baseball("spalding"); // CE 4. Object obj = new Baseball("spalding"); Tossable tossable = obj; // Neither // Tossable is less general than Object. The second assignment would // require a cast. 5. Tossable tossable = new Baseball("spalding"); Object obj = tossable; // CE 6. Tossable tossable = new Baseball("spalding"); tossable.getBrandName(); // Neither // The getBrandName method is not accessible using a variable of // type Tossable even though Baseball objects provide that method.
toss
or bounce
methods. public interface Tossable { void toss(); }
public abstract class Ball implements Tossable { private String brandName; public Ball(String brandName) { this.brandName = brandName; } public String getBrandName() { return brandName; } public abstract void bounce(); }
public class Baseball extends Ball { public Baseball(String brandName) { super(brandName); } public void toss() { } public void bounce() { } }
public class Football extends Ball { public Football(String brandName) { super(brandName); } public void toss() { } public void bounce() { } }
public class Rock implements Tossable { public void toss() { } }