Hypernym and Hyponym
We use the word hyponym for the opposite type of relationship.
- “dog”: Hypernym of “poodle”, “malamute”, “dachshund”, etc.
- “poodle”: Hyponym of “dog”
Hypernyms and hyponyms comprise a hierarchy.
- A dog “is-a” canine.
- A canine “is-a” carnivore.
- A carnivore “is-an” animal.
Interface
- Interface is a specification of what a class is able to do, not how to do it.
Overriding vs. Overloading
- If a “subclass” has a method with the exact same signature as in the “superclass”, we say the subclass overrides the method.
- Methods with the same name but different signatures are overloaded.
- the @Override annotation: the only effect of this tag is that the code won’t compile if it is not actually an overriding method.
Interface Inheritance
Specifying the capabilities of a subclass using the implements keyword is known as interface inheritance.
- Interface: The list of all method signatures.
- Inheritance: The subclass “inherits” the interface from a superclass.
- Specifies what the subclass can do, but not how.
- Subclasses must override all of these methods!
Implementation Inheritance: Default Methods
Use the default keyword to specify a method that subclasses should inherit from an interface.
- If you don’t like a default method, you can override it.
Static and Dynamic Type, Dynamic Method Selection
Every variable in Java has a “compile-time type”, a.k.a. “static type”.
- This is the type specified at declaration.
Variables also have a “run-time type”, a.k.a. “dynamic type”.
- This is the type specified at instantiation (e.g. when using new).
- Equal to the type of the object being pointed at.
Suppose we call a method of an object using a variable with:
- compile-time type X
- run-time type Y
Then if Y overrides the method, Y’s method is used instead.
- If we have a variable has static type
X
and dynamic typeY
, then ifY
overrides the method,Y
's method is used instead.- At compile time, the compiler will verify
X
has a method that can handle the given parameter. If multiple methods can handle, it records the most specific one.- At runtime, if
Y
overrides the recorded signature, use the overridden method.
Implementation Inheritance: Extends
When a class is a hyponym of an interface, we used implements. If you want one class to be a hyponym of another class, you use extends.
- All instance and static variables.
- All methods.
- All nested classes.
Constructor are not inherited.
Type Checking and Casting
- Compiler allows method calls based on compile-time type of variable.
- Compiler also allows assignments based on compile-time types.
Expressions have compile-time types:
- An expression using the new keyword has the specified compile-time type.
- Method calls have compile-time type equal to their declared type.
Java has a special syntax for specifying the compile-time type of any expression.
- Put desired type in parenthesis before the expression.
- Compile-time type Dog:
maxDog(frank, frankJr);
- Compile-time type Poodle:
(Poodle) maxDog(frank, frankJr);
- Compile-time type Dog:
Subtype Polymorphism
Polymorphism: “providing a single interface to entities of different types”
Interfaces and Abstract Classes
implements and extends can be used to enable interface inheritance and implementation inheritance.
- Interface inheritance: What (the class can do).
- Implementation inheritance: How (the class does it).
Interfaces may combine a mix of abstract and default methods.
- Abstract methods are what. And must be overridden by subclass.
- Default methods are how.
- Unless you use the keyword default, a method will be abstract.
- Unless you specify an access modifier, a method will be public.
- Can provide variables, but they are public static final.
- A class can implement multiple interfaces.
- Cannot be instantiated.
- Java 9 added private methods to interfaces.
Abstract classes are an intermediate level between interfaces and classes.
- Cannot be instantiated.
- Can provide either abstract or concrete methods.
- Use abstract keyword for abstract methods.
- Use no keyword for concrete methods.
- Can provide variables (any kind).
- Can provide protected and package private methods.
Abstract classes are often used as partial implementations as interfaces.
Interfaces:
- Primarily for interface inheritance. Limited implementation inheritance.
- Classes can implement multiple interfaces.
Abstract classes:
- Can do anything an interface can do, and more.
- Subclasses only extend one abstract class.
Generalized Comparison
Comparables
The industrial strength approach: Use the built-in Comparable interface.
Already defined and used by tons of libraries. Uses generics.
public interface Comparable<T> {
public int compareTo(T obj);
}
- Lots of built in classes implement Comparable (e.g. String).
- Lots of libraries use the Comparable interface (e.g. Arrays.sort)
- Avoids need for casts.
public class Dog implements Comparable<Dog> {
public int compareTo(Dog uddaDog) {
return this.size - uddaDog.size;
}
Comparators
In some languages, we’d write two comparison functions and simply pass the one we want :
- sizeCompare()
- nameCompare()
The standard Java approach: Create sizeComparator and nameComparator classes that implement the Comparator interface.
- Requires methods that also take Comparator arguments
public interface Comparator<T> {
int compare(T o1, T o2);
}
public class Dog implements Comparable<Dog> {
private String name;
private int size;
public static class NameComparator implements Comparator<Dog> {
public int compare(Dog d1, Dog d2) {
return d1.name.compareTo(d2.name);
}
}
...
}