Answer Key - Abstraction Lab

3 Basics:

This part of the lab will help you understand the basics of abstract classes.

1. Edit TwoPartMeasure.java.

2.Remove the abstract modifier from the declaration of the TwoPartMeasure class and the declaration of the initializeUnits method.

3.Compile the TwoPartMeasure class.

4.What error was generated?

TwoPartMeasure.java:112: missing method body, or declare abstract
protected void initializeUnits();

5.Replace the two abstract modifiers.

6.Compile the TwoPartMeasure class.

7.Why does this class compile even though it has a method with a missing method body?

Abstract classes are not intended to be instantiated. The abstract method is intended as a requirement of any children that use this class as a base. The children who are not abstract must implement this method.

8."Comment out" the initializeUnits method.

9.Compile the TwoPartMeasure class.

10.What error was generated?

TwoPartMeasure.java:61: cannot find symbol
symbol : method initializeUnits()
location: class TwoPartMeasure
initializeUnits();

We get this message because initializeUnits is used in the constructor of a two part measure. So we must have something that the compiler can use to evaluate that statement.

11."Un-comment out" the initializeUnits method.

12.Edit Driver0.java.

13.Compile Driver0.java.

14.What error was generated and why?

Driver0.java:20: TwoPartMeasure is abstract; cannot be instantiated
measure = new TwoPartMeasure();

15.Why doesn't the declaration of the measure variable generate a compile-time error?

By declaring a variable as a TwoPartMeasure, we can instantiate it to any of its concrete children. So the declaration of the abstract type is allowed, but not the instantiation.

4 Specializing an Abstract Class:

This part of the lab will help you understand extensions/specializations of abstract classes.

1.Edit Length.java.

2.Is this class "concrete"? Why or why not?

It is concrete because it is not declared an abstract class, nor does it have any abstract methods.

3.Edit Driver1.java.

4.Compile and execute Driver1.

5.What output was generated?

Age 12:
Mike: 5 feet 5 inches
Bill: 5 feet 5 inches
== SAME ==

Age 16:
Mike: 5 feet 5 inches
Bill: 5 feet 9 inches
== DIFFERENT ==

Age 20:
Mike: 6 feet 6 inches
Bill: 6 feet 7 inches
== DIFFERENT ==

Age 70:
Mike: 6 feet 6 inches
Bill: 6 feet 6 inches
== SAME ==

6.Is this output correct?

Yes

7."Comment out" the implementation of the initializeUnits() in the Length class.

8.Compile the Length class.

9.What error was generated?

Length.java:10: Length is not abstract and does not override abstract method initializeUnits() in TwoPartMeasure
public class Length extends TwoPartMeasure

10."Un-comment out" the implementation of the initializeUnits() in the Length class.

11.Create a Weight class (containing pounds and ounces) that extends the TwoPartMeasure class.

12.What code did you have in your implementation?

See Weight.java.

Besides the changes in variable names and documentation to correspond to weights, the major code change came with the initializeUnits() method.

5 Type Saftey and Abstract Classes:

This part of the lab will help you understand "type saftey" issues that sometimes arise with specializations of abstract classes.

1.Edit Driver2.java.

2.Compile the Driver2 class.

3.Why doesn't the expression myLength.equals(myWeight) generate a compile-time error?

Since the equals method is in the parent class, and both Length and Weight are children, the Length object can send the equals message using the Weight class as a parameter. The compiler will not care that the two are siblings.

4.Execute Driver2.

5.What output is generated?

Length
Expected: 2 feet 1 inch
Actual: 2 feet 1 inch

Weight
Expected: 1 pound 9 ounces
Actual: 1 pound 9 ounces

An Unusual Comparison
The weight equals the length

6.Why does the weight equal the length in the example above? (Note: We will see how this "problem" can be fixed later in the semester.)

The parent class method simply converts the length and weight to the smallest unit and compares the result. In this case, the Length value will be 25 and the weight value will be 25. It is not doing any kind of logic to insure that we are comparing the same types of things.

6 Using Abstract (and Concrete) Classes:

This part of the lab will help you understand some of the ways in which abstract classes and their concrete children are used.

1.Edit LengthDatabase.java and DatabaseDriver1.java.

2.Compile and execute DatabaseDriver1.

3.Did it execute correctly?

Yes.

4.Create a file named DatabaseDriver2.java that creates and store Weight objects in the LengthDatabase rather than Length objects.

5.Compile your implementation of DatabaseDriver2.

6.Why didn't it compile?

DatabaseDriver2.java:26: add(java.lang.String,Length) in LengthDatabase cannot be applied to (java.lang.String,Weight)
database.add("Mike", aLength);

It didn't compile because the add method in LengthDatabase requires a Length object and the Weight object is a sibling and not in the inheritance line with Length. They are then treated as two different kinds of objects.

7.Edit MeasurementDatabase.

8.Modify DatabaseDriver1 and DatabaseDriver2 so that they declare and instantiate MeasurementDatabase objects.

9.Compile DatabaseDriver1.

10.What error was generated?

DatabaseDriver1.java:41: incompatible types

found : TwoPartMeasure
required: Length
result = database.get(name);

By using the MeasurementDatabase, which is based on the abstract TwoPartMeasure class, we are trying to store a parent into a child, but as we saw with polymorphism the child is-a parent, but a parent is not a child. Therefore we cannot use a generic MeasurementDatabase when we want to work with the more specific objects.

11.Correct this error (and the corresponding error in DatabaseDriver2 by casting the value returned by database.get(name) to the appropriate type.

12. What changes did you make?

result = (Length)(database.get(name));