The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.
Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by Oscar Gracias, 2019-02-04 21:04:21

Chapter 9: Inheritance

chapter 9

9.6 Case Study: Financial Class Hierarchy 605

8 }
9
10 // returns this cash investment's market value, which
11 // is equal to the amount of cash
12 public double getMarketValue() {
13
14 return amount;
15 }
16
17 // since cash is a fixed asset, it never has any profit
18 public double getProfit() {
19
20 return 0.0;
21 }
22
23 // sets the amount of cash invested to the given value
24 public void setAmount(double amount) {
25 }
this.amount = amount;
}

As we discussed earlier in this chapter, a DividendStock is very similar to a
normal Stock, but it has a small amount of behavior added. Let’s display
DividendStock as a subclass of Stock through inheritance, matching the design
from earlier in the chapter. Figure 9.8 shows how our hierarchy should now look.

<<interface>>
Asset

getMarketValue()
getProfit()

Stock MutualFund Cash
symbol symbol amount
total shares: int total shares: double getMarketValue()
total cost total cost getProfit()
current price current price
getMarketValue() getMarketValue()
getProfit() getProfit()

DividendStock
dividends
getMarketValue()
getProfit()

Figure 9.8 Financial class hierarchy

606 Chapter 9 Inheritance and Interfaces

What about the similarity between mutual funds and stocks? They both store
assets that are based on shares, with a symbol, total cost, and current price. It wouldn’t
work very well to make one of them a subclass of the other, though, because the type
of shares (integer or real number) isn’t the same, and also because it’s not a sensible
is-a relationship: stocks aren’t really mutual funds, and vice versa. It might seem
excessive to have a separate class for mutual funds when the only difference is the
existence of partial shares. But conceptually, these are separate types of investments,
and many investors want to keep them separate. Also, there are some aspects of
mutual funds, such as tax ramifications and Morningstar ratings, that are unique and
that we might want to add to the program later.

Let’s modify our design by making a new superclass called ShareAsset which
represents any asset that has shares and that contains the common behavior of Stock
and MutualFund. Then we can have both Stock and MutualFund extend
ShareAsset, to reduce redundancy.

Our previous versions of the Stock and DividendStock classes each had a
getProfit method that required a parameter for the current price per share. In order
to implement the Asset interface with its parameterless getMarketValue and
getProfit methods, we’ll change our design and create a field for the current price.
We’ll also add methods to get and set the value of the current price. The updated type
hierarchy is shown in Figure 9.9.

This practice of redesigning code to meet new requirements is sometimes called
refactoring.

<<interface>>
Asset

getMarketValue()
getProfit()

ShareAsset
symbol
total cost
current price
getProfit

Stock MutualFund Cash
total shares: int total shares: double amount
getMarketValue() getMarketValue() getMarketValue()
getProfit()
DividendStock
dividends
getMarketValue()

Figure 9.9 Updated financial class hierarchy

9.6 Case Study: Financial Class Hierarchy 607

Refactoring

Changing a program’s internal structure without modifying its external
behavior to improve simplicity, readability, maintainability, extensibility,
performance, etc.

Redundant Implementation

Here’s some potential code for the ShareAsset class:

1 // A ShareAsset object represents a general asset that has a symbol
2 // and holds shares. Initial version.
3 public class ShareAsset {
4 private String symbol;
5 private double totalCost;
6 private double currentPrice;
7
8 // constructs a new share asset with the given symbol
9 // and current price
10 public ShareAsset(String symbol, double currentPrice) {
11 this.symbol = symbol;
12 this.currentPrice = currentPrice;
13 totalCost = 0.0;
14 }
15
16 // adds a cost of the given amount to this asset
17 public void addCost(double cost) {
18 totalCost += cost;
19 }
20
21 // returns the price per share of this asset
22 public double getCurrentPrice() {
23 return currentPrice;
24 }
25
26 // returns this asset's total cost for all shares
27 public double getTotalCost() {
28 return totalCost;
29 }
30
31 // sets the current share price of this asset
32 public void setCurrentPrice(double currentPrice) {
33 this.currentPrice = currentPrice;
34 }
35 }

608 Chapter 9 Inheritance and Interfaces

We stole some code from the Stock class and then made a few changes so that the
code would fit this interface. Our Stock code accepted the current share price as a
parameter to its getProfit method. Since the getProfit method cannot accept any
parameters if we wish to implement the interface, we’ll instead store the current
share price as a field in the ShareAsset class and supply a setCurrentPrice muta-
tor method that can be called to set its proper value. We also include a constructor
that can initialize a Stock object with any number of shares and a total cost.

One last modification we made in creating ShareAsset was to include an
addCost method, which we’ll use to add a given amount to the asset’s total cost. We
will need this because purchases of Stocks and MutualFunds need to update the
totalCost field, but they cannot do so directly because it is private.

The Stock class can now extend ShareAsset to implement its remaining func-
tionality. Notice that we both extend ShareAsset and implement the Asset interface
in the class’s header:

1 // A Stock object represents purchases of shares of a stock.
2 // Initial version.
3 public class Stock extends ShareAsset implements Asset {
4 private int totalShares;
5
6 // constructs a new Stock with the given symbol and
7 // current price per share
8 public Stock(String symbol, double currentPrice) {
9 super(symbol, currentPrice);
10 totalShares = 0;
11 }
12
13 // returns the market value of this stock, which is
14 // the number of total shares times the share price
15 public double getMarketValue() {
16 return totalShares * getCurrentPrice();
17 }
18
19 // returns the total number of shares purchased
20 public int getTotalShares() {
21 return totalShares;
22 }
23
24 // returns the profit made on this stock
25 public double getProfit() {
26 return getMarketValue() – getTotalCost();
27 }
28
29 // records a purchase of the given number of shares of

9.6 Case Study: Financial Class Hierarchy 609

30 // the stock at the given price per share
31 public void purchase(int shares, double pricePerShare) {
32
33 totalShares += shares;
34 addCost(shares * pricePerShare);
35 } }

The MutualFund class receives similar treatment, but with a double for its total
shares (the two classes are highly redundant; we’ll improve them in the next section):

1 // A MutualFund object represents a mutual fund asset.
2 // Initial version.
3 public class MutualFund extends ShareAsset implements Asset {
4 private double totalShares;
5
6 // constructs a new MutualFund investment with the given
7 // symbol and price per share
8 public MutualFund(String symbol, double currentPrice) {
9 super(symbol, currentPrice);
10 totalShares = 0.0;
11 }
12
13 // returns the market value of this mutual fund, which
14 // is the number of shares times the price per share
15 public double getMarketValue() {
16 return totalShares * getCurrentPrice();
17 }
18
19 // returns the number of shares of this mutual fund
20 public double getTotalShares() {
21 return totalShares;
22 }
23
24 // returns the profit made on this mutual fund
25 public double getProfit() {
26 return getMarketValue() – getTotalCost();
27 }
28
29 // records purchase of the given shares at the given price
30 public void purchase(double shares, double pricePerShare) {
31 totalShares += shares;
32 addCost(shares * pricePerShare);
33 }
34 }

610 Chapter 9 Inheritance and Interfaces

The DividendStock simply adds an amount of dividend payments to a normal
Stock, which affects its market value. We don’t need to override the getProfit
method in DividendStock, because DividendStock already inherits a getProfit
method with the following body:

return getMarketValue() – getTotalCost();

Notice that getProfit’s body calls getMarketValue. The DividendStock class
overrides the getMarketValue method, with the convenient side effect that any
other method that calls getMarketValue (such as getProfit) will also behave dif-
ferently. This occurs because of polymorphism; since getMarketValue is overrid-
den, getProfit calls the new version of the method. The profit will be correctly
computed with dividends because the dividends are added to the market value.

The following code implements the DividendStock class:

1 // A DividendStock object represents a stock purchase that also pays
2 // dividends.
3 public class DividendStock extends Stock {
4 private double dividends; // amount of dividends paid
5
6 // constructs a new DividendStock with the given symbol
7 // and no shares purchased
8 public DividendStock(String symbol, double currentPrice) {
9 super(symbol, currentPrice); // call Stock constructor
10 dividends = 0.0;
11 }
12
13 // returns this DividendStock's market value, which is
14 // a normal stock's market value plus any dividends
15 public double getMarketValue() {
16 return super.getMarketValue() + dividends;
17 }
18
19 // records a dividend of the given amount per share
20 public void payDividend(double amountPerShare) {
21 dividends += amountPerShare * getTotalShares();
22 }
23 }

Abstract Classes

So far we have written classes, which are concrete implementations of state and
behavior, and interfaces, which are completely abstract declarations of behavior.
There is an entity that exists between these two extremes, allowing us to define some

9.6 Case Study: Financial Class Hierarchy 611

concrete state and behavior while leaving some abstract, without defined method
bodies. Such an entity is called an abstract class.

Abstract Class

A Java class that cannot be instantiated, but that instead serves as a super-
class to hold common code and declare abstract behavior.

You probably noticed a lot of redundancy between the Stock and MutualFund
code in the last section. For example, although the getMarketValue and getProfit
methods have identical code, they can’t be moved up into the ShareAsset superclass
because they depend on the number of shares, which is different in each child class.
Ideally, we should get rid of this redundancy somehow.

There is also a problem with our current ShareAsset class. A ShareAsset isn’t
really a type of asset that a person can buy; it’s just a concept that happens to be rep-
resented in our code. It would be undesirable for a person to actually try to construct
a ShareAsset object—we wrote the class to eliminate redundancy, not for clients to
instantiate it.

We can resolve these issues by designating the ShareAsset class as abstract.
Writing abstract in a class’s header will modify the class in two ways. First, the class
becomes noninstantiable, so client code will not be allowed to construct an object of
that type with the new keyword. Second, the class is enabled to declare abstract
methods without bodies. Unlike an interface, though, an abstract class can also
declare fields and implement methods with bodies, so the ShareAsset class can
retain its existing code.

The general syntax for declaring an abstract class is

public abstract class <name> {
...

}

Thus, our new ShareAsset class header will be

public abstract class ShareAsset {
...

}

An attempt to create a ShareAsset object will now produce a compiler error such
as the following:

ShareAsset is abstract; cannot be instantiated
ShareAsset asset = new ShareAsset("MSFT", 27.46);


1 error

612 Chapter 9 Inheritance and Interfaces

Really, the Employee class introduced earlier in this chapter should also have been
an abstract class. We did not especially want client code to construct Employee
objects. No one is just an employee; the Employee class merely represented a general
category that we wanted the other classes to extend.

Abstract classes are allowed to implement interfaces. Rather than requiring all
subclasses of ShareAsset to implement the Asset interface, we can specify that
ShareAsset implements Asset:

public abstract class ShareAsset implements Asset {
...

}

This indication will save ShareAsset subclasses from having to write implements
Asset in their class headers.

ShareAsset does not implement the getMarketValue method required by
Asset; that functionality is left for its subclasses. We can instead declare
getMarketValue as an abstract method in the ShareAsset class. Abstract methods
declared in abstract classes need to have the keyword abstract in their headers in
order to compile properly. Otherwise, the syntax is the same as when we declare an
abstract method in an interface, with a semicolon replacing the method’s body:

// returns the current market value of this asset
public abstract double getMarketValue();

The general syntax for an abstract method declaration in an abstract class is the
following:

public abstract <type> <name> (<type> <name>, ..., <type> <name>);

Another benefit of this design is that code in the abstract class can actually call
any of its abstract methods, even if they don’t have implementations in that file. This
is allowed because the abstract class can count on its subclasses to implement the
abstract methods. Now that ShareAsset implements Asset, we can move the
common redundant getProfit code up to ShareAsset and out of Stock and
MutualFund:

// returns the profit earned on shares of this asset
public double getProfit() {

// calls an abstract getMarketValue method
// (the subclass will provide its implementation)
return getMarketValue() – totalCost;
}

ShareAsset objects can call getMarketValue from their getProfit methods
even though that method isn’t present in ShareAsset. The code compiles because

9.6 Case Study: Financial Class Hierarchy 613

the compiler knows that whatever class extends ShareAsset will have to implement
getMarketValue.

The following is the final version of the ShareAsset abstract class:

1 // A ShareAsset represents a general asset that has a symbol and
2 // holds shares.
3 public abstract class ShareAsset implements Asset {
4 private String symbol;
5 private double totalCost;
6 private double currentPrice;
7
8 // constructs a new share asset with the given symbol
9 // and current price
10 public ShareAsset(String symbol, double currentPrice) {
11 this.symbol = symbol;
12 this.currentPrice = currentPrice;
13 totalCost = 0.0;
14 }
15
16 // adds a cost of the given amount to this asset
17 public void addCost(double cost) {
18 totalCost += cost;
19 }
20
21 // returns the price per share of this asset
22 public double getCurrentPrice() {
23 return currentPrice;
24 }
25
26 // returns the current market value of this asset
27 public abstract double getMarketValue();
28
29 // returns the profit earned on shares of this asset
30 public double getProfit() {
31 // calls an abstract getMarketValue method
32 // (the subclass will provide its implementation)
33 return getMarketValue() – totalCost;
34 }
35
36 // returns this asset's total cost for all shares
37 public double getTotalCost() {
38 return totalCost;
39 }

614 Chapter 9 Inheritance and Interfaces

40 // sets the current share price of this asset
41 public void setCurrentPrice(double currentPrice) {
42
43 this.currentPrice = currentPrice;
44 }
45 }

An abstract class is a useful hybrid that can contain both abstract and nonabstract
methods. All methods declared in an interface are implicitly abstract; they can be
declared with the abstract keyword if you wish. Declaring them without the abstract
keyword as we have done in this chapter is a commonly used shorthand for the
longer explicit form. Unfortunately, abstract classes disallow this shorthand to avoid
ambiguity.

Nonabstract classes like Stock and MutualFund are sometimes called concrete
classes to differentiate them from abstract classes. We can modify the Stock and
MutualFund classes to take advantage of ShareAsset and reduce redundancy. The
following are the final versions of the Stock and MutualFund classes.
(DividendStock is unmodified.) Notice that the subclasses of ShareAsset must
implement getMarketValue, or we’ll receive a compiler error:

1 // A Stock object represents purchases of shares of a stock.
2 public class Stock extends ShareAsset {
3 private int totalShares;
4
5 // constructs a new Stock with the given symbol and
6 // current price per share
7 public Stock(String symbol, double currentPrice) {
8 super(symbol, currentPrice);
9 totalShares = 0;
10 }
11
12 // returns the market value of this stock, which is
13 // the number of total shares times the share price
14 public double getMarketValue() {
15 return totalShares * getCurrentPrice();
16 }
17
18 // returns the total number of shares purchased
19 public int getTotalShares() {
20 return totalShares;
21 }
22
23 // records a purchase of the given number of shares of
24 // the stock at the given price per share

9.6 Case Study: Financial Class Hierarchy 615

25 public void purchase(int shares, double pricePerShare) {
26 totalShares += shares;
27 addCost(shares * pricePerShare);
28
29 } }

1 // A MutualFund object represents a mutual fund asset.
2 public class MutualFund extends ShareAsset {
3 private double totalShares;
4
5 // constructs a new MutualFund investment with the given
6 // symbol and price per share
7 public MutualFund(String symbol, double currentPrice) {
8 super(symbol, currentPrice);
9 totalShares = 0.0;
10 }
11
12 // returns the market value of this mutual fund, which
13 // is the number of shares times the price per share
14 public double getMarketValue() {
15 return totalShares * getCurrentPrice();
16 }
17
18 // returns the number of shares of this mutual fund
19 public double getTotalShares() {
20 return totalShares;
21 }
22
23 // records purchase of the given shares at the given price
24 public void purchase(double shares, double pricePerShare) {
25 totalShares += shares;
26 addCost(shares * pricePerShare);
27 }
28 }

Abstract classes can do everything interfaces can do and more, but this does not
mean that it is always better to use them than interfaces. One important difference
between interfaces and abstract classes is that a class may choose to implement arbi-
trarily many interfaces, but it can extend just one abstract class. That is why an inter-
face often forms the top of an inheritance hierarchy, as our Asset interface did in this
design. Such placement allows classes to become part of the hierarchy without having
it consume their only inheritance relationships.

616 Chapter 9 Inheritance and Interfaces

Chapter Summary

Inheritance is a feature of Java programs that allows the may be a poor design choice and a “has-a” relationship
creation of a parent–child relationship between two types. between them (in which one object contains the other as a
field) may be better.

The child class of an inheritance relationship (commonly An interface is a list of method declarations. An interface
called a subclass) will receive a copy of (“inherit”) every specifies method names, parameters, and return types but
field and method from the parent class (superclass). The sub- does not include the bodies of the methods. A class can
class “extends” the superclass, because it can add new fields implement (i.e., promise to implement all of the methods
and methods to the ones it inherits from the superclass. of) an interface.

A subclass can override a method from the superclass by Interfaces help us achieve polymorphism so that we can
writing its own version, which will replace the one that treat several different classes in the same way. If two or
was inherited. more classes both implement the same interface, we can
use either of them interchangeably and can call any of the
Treating objects of different types interchangeably is interface’s methods on them.
called polymorphism.

Subclasses can refer to the superclass’s constructors or An abstract class cannot be instantiated. No objects of the
methods using the super keyword. abstract type can be constructed. An abstract class is use-
ful because it can be used as a superclass and can also
The Object class represents the common superclass of all define abstract behavior for its subclasses to implement.
objects and contains behavior that every object should
have, such as the equals and toString methods. An abstract class can contain abstract methods, which are
declared but do not have bodies. All subclasses of an
Inheritance provides an “is-a” relationship between two abstract class must implement the abstract superclass’s
classes. If the two classes are not closely related, inheritance abstract methods.

Self-Check Problems

Section 9.1: Inheritance Basics
1. What is code reuse? How does inheritance help achieve code reuse?
2. What is the difference between overloading and overriding a method?
3. Consider the following classes:

public class Vehicle {...}
public class Car extends Vehicle {...}
public class SUV extends Car {...}

Self-Check Problems 617

Which of the following are legal statements?

a. Vehicle v = new Car();
b. Vehicle v = new SUV();
c. Car c = new SUV();
d. SUV s = new SUV();
e. SUV s = new Car();
f. Car c = new Vehicle();

Section 9.2: Interacting with the Superclass
4. Explain the difference between the this keyword and the super keyword. When should each be used?

5. For the next three problems, consider the following class:

1 // Represents a university student.
2 public class Student {

3 private String name;
4 private int age;

5
6 public Student(String name, int age) {

7 this.name = name;
8 this.age = age;

9}
10

11 public void setAge(int age) {
12 this.age = age;

13 }
14 }

Also consider the following partial implementation of a subclass of Student to represent undergraduate students at
a university:

public class UndergraduateStudent extends Student {
private int year;
...

}

Can the code in the UndergraduateStudent class access the name and age fields it inherits from Student? Can
it call the setAge method?

6. Write a constructor for the UndergraduateStudent class that accepts a name as a parameter and initializes the
UnderGraduateStudent’s state with that name, an age value of 18, and a year value of 0.

7. Write a version of the setAge method in the UndergraduateStudent class that not only sets the age but also
increments the year field’s value by one.

Section 9.3: Polymorphism
8. Using the A, B, C, and D classes from this section, what is the output of the following code fragment?

public static void main(String[] args) {
A[] elements = {new B(), new D(), new A(), new C()};

618 Chapter 9 Inheritance and Interfaces

for (int i = 0; i < elements.length; i++) {
elements[i].method2();
System.out.println(elements[i]);
elements[i].method1();
System.out.println();

}
}

9. Assume that the following classes have been defined:

1 public class Flute extends Blue {
2 public void method2() {
3 System.out.println("flute 2");
4}
5
6 public String toString() {
7 return "flute";
8}
9}

1 public class Blue extends Moo {
2 public void method1() {
3 System.out.println("blue 1");
4}
5}

1 public class Shoe extends Flute {
2 public void method1() {
3 System.out.println("shoe 1");
4}
5}

1 public class Moo {
2 public void method1() {
3 System.out.println("moo 1");
4}
5
6 public void method2() {
7 System.out.println("moo 2");
8}
9
10 public String toString() {
11 return "moo";
12 }
13 }

Self-Check Problems 619

What is the output produced by the following code fragment?

public static void main(String[] args) {
Moo[] elements = {new Shoe(), new Flute(), new Moo(), new Blue()};
for (int i = 0; i < elements.length; i++) {
System.out.println(elements[i]);
elements[i].method1();
elements[i].method2();
System.out.println();
}

}

10. Using the classes from the previous problem, write the output that is produced by the following code fragment.

public static void main(String[] args) {
Moo[] elements = {new Blue(), new Moo(), new Shoe(), new Flute()};
for (int i = 0; i < elements.length; i++) {
elements[i].method2();
elements[i].method1();
System.out.println(elements[i]);
System.out.println();
}

}

11. Assume that the following classes have been defined:

1 public class Mammal extends SeaCreature {
2 public void method1() {
3 System.out.println("warm-blooded");
4}
5}

1 public class SeaCreature {
2 public void method1() {
3 System.out.println("creature 1");
4}
5
6 public void method2() {
7 System.out.println("creature 2");
8}
9
10 public String toString() {
11 return "ocean-dwelling";
12 }
13 }

620 Chapter 9 Inheritance and Interfaces

1 public class Whale extends Mammal {
2 public void method1() {
3 System.out.println("spout");
4}
5
6 public String toString() {
7 return "BIG!";
8}
9}

1 public class Squid extends SeaCreature {
2 public void method2() {
3 System.out.println("tentacles");
4}
5
6 public String toString() {
7 return "squid";
8}
9}

What output is produced by the following code fragment?

public static void main(String[] args) {
SeaCreature[] elements = {new Squid(), new Whale(),
new SeaCreature(), new Mammal()};
for (int i = 0; i < elements.length; i++) {
System.out.println(elements[i]);
elements[i].method1();
elements[i].method2();
System.out.println();
}

}

12. Using the classes from the previous problem, write the output that is produced by the following code fragment:

public static void main(String[] args) {
SeaCreature[] elements = {new SeaCreature(),
new Squid(), new Mammal(), new Whale()};
for (int i = 0; i < elements.length; i++) {
elements[i].method2();
System.out.println(elements[i]);
elements[i].method1();
System.out.println();
}

}

Self-Check Problems 621

13. Assume that the following classes have been defined:

1 public class Bay extends Lake {
2 public void method1() {
3 System.out.print("Bay 1 ");
4 super.method2();
5}
6 public void method2() {
7 System.out.print("Bay 2 ");
8}
9}

1 public class Pond {
2 public void method1() {
3 System.out.print("Pond 1 ");
4}
5 public void method2() {
6 System.out.print("Pond 2 ");
7}
8 public void method3() {
9 System.out.print("Pond 3 ");
10 }
11 }

1 public class Ocean extends Bay {
2 public void method2() {
3 System.out.print("Ocean 2 ");
4}
5}

1 public class Lake extends Pond {
2 public void method3() {
3 System.out.print("Lake 3 ");
4 method2();
5}
6}

What output is produced by the following code fragment?

Pond[] ponds = {new Ocean(), new Pond(), new Lake(), new Bay()};
for (Pond p : ponds) {

p.method1();
System.out.println();
p.method2();
System.out.println();
p.method3();
System.out.println("\n");
}

622 Chapter 9 Inheritance and Interfaces

14. Suppose that the following variables referring to the classes from the previous problem are declared:

Pond var1 = new Bay();
Object var2 = new Ocean();
Which of the following statements produce compiler errors? For the statements that do not produce errors, what is
the output of each statement?

((Lake) var1).method1();
((Bay) var1).method1();
((Pond) var2).method2();
((Lake) var2).method2();
((Ocean) var2).method3();

Section 9.4: Inheritance and Design
15. What is the difference between an is-a and a has-a relationship? How do you create a has-a relationship in your code?

16. Imagine a Rectangle class with objects that represent two-dimensional rectangles. The Rectangle has width and
height fields with appropriate accessors and mutators, as well as getArea and getPerimeter methods.

You would like to add a Square class into your system. Is it a good design to make Square a subclass of
Rectangle? Why or why not?
17. Imagine that you are going to write a program to play card games. Consider a design with a Card class and 52 sub-
classes, one for each of the unique playing cards (for example, NineOfSpades and JackOfClubs). Is this a good
design? If so, why? If not, why not, and what might be a better design?

18. In Section 9.2 we discussed adding functionality for dividend payments to the Stock class. Why was it preferable to
create a DividendStock class rather than editing the Stock class and adding this feature directly to it?

Section 9.5: Interfaces
19. What is the difference between implementing an interface and extending a class?

20. Consider the following interface and class:

public interface I {
public void m1();
public void m2();

}

public class C implements I {
// code for class C

}
What must be true about the code for class C in order for that code to compile successfully?
21. What’s wrong with the code for the following interface? What should be changed to make a valid interface for
objects that have colors?

public interface Colored {
private Color color;
public Color getColor() {
return color;
}

}

Exercises 623

22. Modify the Point class from Chapter 8 so that it implements the Colored interface and Points have colors. (You
may wish to create a ColoredPoint class that extends Point.)

23. Declare a method called getSideCount in the Shape interface that returns the number of sides that the shape has.
Implement the method in all shape classes. A circle is defined to have 0 sides.

Section 9.6: Case Study: Financial Class Hierarchy

24. What is an abstract class? How is an abstract class like a normal class, and how does it differ? How is it like an interface?

25. Consider writing a program to be used to manage a collection of movies. There are three kinds of movies in the
collection: dramas, comedies, and documentaries. The collector would like to keep track of each movie’s title, the
name of its director, and the year the movie was made. Some operations are to be implemented for all movies, and
there will also be special operations for each of the three different kinds of movies. How would you design the
class(es) to represent this system of movies?

Exercises

1. Write the class Marketer to accompany the other law firm classes described in this chapter. Marketers make
$50,000 ($10,000 more than general employees) and have an additional method called advertise that prints
"Act now, while supplies last!" Make sure to interact with the superclass as appropriate.

2. Write a class Janitor to accompany the other law firm classes described in this chapter. Janitors work twice as
many hours per week as other employees (80 hours/week), they make $30,000 ($10,000 less than general employ-
ees), they get half as much vacation as other employees (only 5 days), and they have an additional method clean
that prints "Workin' for the man." Make sure to interact with the superclass as appropriate.

3. Write a class HarvardLawyer to accompany the other law firm classes described in this chapter. Harvard lawyers
are like normal lawyers, but they make 20% more money than a normal lawyer, they get 3 days more vacation, and
they have to fill out four of the lawyer’s forms to go on vacation. That is, the getVacationForm method should
return "pinkpinkpinkpink". Make sure to interact with the superclass as appropriate.

4. For the next four problems, consider the task of representing types of tickets to campus events. Each ticket has a
unique number and a price. There are three types of tickets: walk-up tickets, advance tickets, and student advance
tickets. Figure 9.10 illustrates the types:

• Walk-up tickets are purchased the day of the event and cost $50.
• Advance tickets purchased 10 or more days before the event cost $30, and advance tickets purchased fewer than

10 days before the event cost $40.
• Student advance tickets are sold at half the price of normal advance tickets: When they are purchased 10 or more

days early they cost $15, and when they are purchased fewer than 10 days early they cost $20.

Implement a class called Ticket that will serve as the superclass for all three types of tickets. Define all common
operations in this class, and specify all differing operations in such a way that every subclass must implement them.
No actual objects of type Ticket will be created: Each actual ticket will be an object of a subclass type. Define the
following operations:

• The ability to construct a ticket by number.
• The ability to ask for a ticket’s price.
• The ability to println a ticket object as a String. An example String would be "Number: 17, Price: 50.0".

624 Chapter 9 Inheritance and Interfaces

Ticket
number
Ticket(number)
getPrice()
toString()

Walkup Ticket Advance Ticket

Student Advance Ticket

Figure 9.10 Classes of tickets that are available to campus events

5. Implement a class called WalkupTicket to represent a walk-up event ticket. Walk-up tickets are also constructed by
number, and they have a price of $50.

6. Implement a class called AdvanceTicket to represent tickets purchased in advance. An advance ticket is con-
structed with a ticket number and with the number of days in advance that the ticket was purchased. Advance tickets
purchased 10 or more days before the event cost $30, and advance tickets purchased fewer than 10 days before the
event cost $40.

7. Implement a class called StudentAdvanceTicket to represent tickets purchased in advance by students. A student
advance ticket is constructed with a ticket number and with the number of days in advance that the ticket was pur-
chased. Student advance tickets purchased 10 or more days before the event cost $15, and student advance tickets
purchased fewer than 10 days before the event cost $20 (half of a normal advance ticket). When a student advance
ticket is printed, the String should mention that the student must show his or her student ID (for example,
"Number: 17, Price: 15.0 (ID required)").

8. MinMaxAccount. A company has written a large class BankAccount with many methods including:

public BankAccount(Startup s) Constructs a BankAccount object using information in s
public void debit(Debit d) Records the given debit
public void credit(Credit c) Records the given credit
public int getBalance() Returns the current balance in pennies

Design a new class MinMaxAccount whose instances can be used in place of a bank account but include new behavior
of remembering the minimum and maximum balances ever recorded for the account. The class should have a construc-
tor that accepts a Startup parameter. The bank account’s constructor sets the initial balance on the basis of the startup
information. Assume that only debits and credits change an account’s balance. Include these new methods in your class:

public int getMin() Returns the minimum balance in pennies
public int getMax() Returns the maximum balance in pennies

Exercises 625
9. DiscountBill. Suppose a class GroceryBill keeps track of a list of items being purchased at a market:

public GroceryBill(Employee clerk) Constructs a grocery bill object for the given clerk
public void add(Item i) Adds the given item to this bill
public double getTotal() Returns the total cost of these items
public void printReceipt() Prints a list of items

Grocery bills interact with Item objects, each of which has the public methods that follow. A candy bar item might
cost 1.35 with a discount of 0.25 for preferred customers, meaning that preferred customers get it for 1.10. (Some
items will have no discount, 0.0.) Currently the preceding classes do not consider discounts. Every item in a bill is
charged full price, and item discounts are ignored.

public double getPrice() Returns the price for this item
public double getDiscount() Returns the discount for this item

Define a class DiscountBill that extends GroceryBill to compute discounts for preferred customers. Its con-
structor accepts a parameter for whether the customer should get the discount. Your class should also adjust the total
reported for preferred customers. For example, if the total would have been $80 but a preferred customer is getting
$20 in discounts, then getTotal should report the total as $60 for that customer. Also keep track of the number of
items on which a customer is getting a nonzero discount and the sum of these discounts, both as a total amount and
as a percentage of the original bill. Include the extra methods that follow, which allow a client to ask about the dis-
count. Return 0.0 if the customer is not a preferred customer or if no items were discounted.

public DiscountBill(Employee Constructs bill for given clerk
clerk, boolean preferred)
public int getDiscountCount() Returns the number of items that were discounted, if any
public double getDiscountAmount() Returns the total discount for this list of items, if any
public double getDiscountPercent() Returns the percent of the total discount as a percent of what
the total would have been otherwise

10. FilteredAccount. A cash processing company has a class called Account used to process transactions:

public Account(Client c) Constructs an account using client information
public boolean process(Transaction t) Processes the next transaction, returning true if
the transaction was approved and false otherwise

626 Chapter 9 Inheritance and Interfaces
Account objects interact with Transaction objects, which have many methods including

public int value() Returns the value of this transaction in pennies (could be negative,
positive or zero)

Design a new class called FilteredAccount whose instances can be used in place of normal accounts but which
include the extra behavior of not processing transactions with a value of 0. More specifically, the new class should
indicate that a zero-valued transaction was approved but shouldn’t call the process method for it. Your class should
have a single constructor that accepts a parameter of type Client, and it should include the following method:

public double percentFiltered() Returns the percent of transactions filtered out (between 0.0
and 100.0); returns 0.0 if no transactions are submitted

11. Add an equals method to the TimeSpan class introduced in Chapter 8. Two time spans are considered equal if they
represent the same number of hours and minutes.

12. Add an equals method to the Cash class introduced in this chapter. Two stocks are considered equal if they repre-
sent the same amount of cash.

13. Add an equals method to each of the Rectangle, Circle, and Triangle classes introduced in this chapter. Two
shapes are considered equal if their fields have equivalent values.

14. Write a class named Octagon whose objects represent regular octagons (eight-sided polygons). Your class should
implement the Shape interface defined in this chapter, including methods for its area and perimeter. An Octagon
object is defined by its side length. (You may need to search online to find formulas for the area and perimeter of a
regular octagon.)

15. Write a class named Hexagon whose objects represent regular hexagons (6-sided polygons). Your class should
implement the Shape interface defined in this chapter.

16. Declare an interface called Incrementable which represents items that store an integer that can be incremented in
some way. The interface has a method called increment that increments the value and a method called getValue
that returns the value. Once you have written the interface, write two classes called SequentialIncrementer and
RandomIncrementer that implement the interface. The SequentialIncrementer begins its value at 0 and
increases it by 1 each time it is incremented. The RandomIncrementer begins its value at a random integer and
changes it to a new random integer each time it is incremented.

Programming Projects

1. Write an inheritance hierarchy of three-dimensional shapes. Make a top-level shape interface that has methods for
getting information such as the volume and surface area of a three-dimensional shape. Then make classes and sub-
classes that implement various shapes such as cubes, rectangular prisms, spheres, triangular prisms, cones, and cylin-
ders. Place common behavior in superclasses whenever possible, and use abstract classes as appropriate. Add meth-
ods to the subclasses to represent the unique behavior of each three-dimensional shape, such as a method to get a
sphere’s radius.

Programming Projects 627

2. Write a set of classes that define the behavior of certain animals. They can be used in a simulation of a world with
many animals moving around in it. Different kinds of animals will move in different ways (you are defining those
differences). As the simulation runs, animals can “die” when two or more of them end up in the same location,
in which case the simulator randomly selects one animal to survive the collision. See your course web site or
www.buildingjavaprograms.com for supporting files to run such a simulation.

The following is an example set of animals and their respective behavior:

Class toString getMove

Bird B Moves randomly 1 step in one of the four directions each time
Frog F Moves randomly 3 steps in one of the four directions
Mouse M Moves west 1 step, north 1 step (zig-zag to the northwest)
Rabbit V Move north 2 steps, east 2 steps, south 2 steps (“hops” to the right)
Snake S Moves south 1 step, east 1 step, south 1 step, west 2 steps, south 1 step, east 3 steps, south

Turtle 1 step, west 4 steps, ... (“slithers” left and right in increasing length)
Wolf T Moves south 5 steps, west 5 steps, north 5 steps, east 5 steps (clockwise box)
W Has custom behavior that you define

Your classes should be stored in files called Bird.java, Frog.java, Mouse.java, Rabbit.java, Snake.java, Turtle.java,
and Wolf.java.

3. Write an inheritance hierarchy that stores data about sports players. Create a common superclass and/or interface to
store information common to any player regardless of sport, such as name, number, and salary. Then create sub-
classes for players of your favorite sports, such as basketball, soccer, or tennis. Place sport-specific information and
behavior (such as kicking or vertical jump height) into subclasses whenever possible.

4. Write an inheritance hierarchy to model items at a library. Include books, magazines, journal articles, videos, and
electronic media such as CDs. Include in a superclass and/or interface common information that the library must
have for every item, such as a unique identification number and title. Place behavior and information that is specific
to items, such as a video’s runtime length or a CD’s musical genre, into the subclasses.


Click to View FlipBook Version