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()
{
}
}