SectionC.18J3: Abstract Classes, Object, Overriding and Overloading Methods
Synopsis.
Motivate inheritance of methods by code reuse by means of the Vec2 example.
Multiple variants share code. But code duplication is bad.
The translate method is implemented in both classes. Factor this method out into a super class BaseVec2.
However, setXY is not available in BaseVec.
Make BaseVec2 abstract and declare method setXY abstract in BaseVec2.
Subclasses can always override methods. CartesianVec2 could override translate and provide a more “direct” implementation.
Mention @override. Defer discussion to overloading.
Object
toString used to automatically convert an object to a string. Used by the + operator on strings and many other methods such as System.out.println.
equals() compares objects to be equal (not the same; that is done by the == operator!). We need this if we want to put objects in collections. Make small example, comparing two strings. Implement in BaseVec2.
equals(Vec2) would be nice but does not override equals(Object) that we inherit from Object. @override helps to make clear that we are actually overriding a method. Will cause compile error if we are overloading instead of overriding.
We cannot call getX from equals(Object) because the static type is too weak. instanceof allows for tests on the dynamic type and guard dynamic type casts.
Illustrate subtype relationship by means of a Venn diagram. Make clear that we can always weaken the static type. Strengthening it needs a dynamic cast. Draw connection to assertion lecture: weakening post-condition is always possible.
Using instanceof is bad style and hints at a problem in the design. Sometimes, like in equals it is however necessary. Work as much as possible with static types.
Overloading.
Define signature of method with a certain name: list of parameters including implicit this argument. Return type is not part of signature.
Overloading means that we have multiple methods with the same name but different signature.
Overloaded method is identified at compile type based on the static types of the method's arguments.
In contrast to overriding: identifies method to call at run time based on the dynamic types of the the first (this) argument.
Identification of suitable overloaded method for a call:
Identify set of methods with appropriate number of parameters.
From that, identify set of applicable methods; if set empty: error.
From that set, identify most specific method; if not unique: error.