CS 61B Part 3 Inheritance, Implements, Iterators
prev:[[61B_Part_2_LinkList]]
next:[[part4-Iterators]]
Hug61B chapter4
Part 3 Inheritance, Implements, Iterators
overload
Suppose we want to write a class WordUtilsthat includes functions we can run on lists of words, including a method that calculates the longest string in an SLList.
1 | public static String longest(SLList<String> list) { |
make it suitable for AList?
change the SLList<String> list into the AList<String> list!
coexistence of the two functions are allowed in the function!
(method overloading)
interface
In Java, in order to express this hierarchy, we need to do two things:
Step 1: Define a type for the general list hypernym – we will choose the name List61B.
Step 2: Specify that SLList and AList are hyponyms of that type.
here is the 61B interface:
1 | public interface List61B<Item> { |
then, we define this relationship in the class definition:
1 | public class AList<Item> implements List61B<Item>{...} |
overriding
When implementing the required functions in the subclass, it’s useful (and actually required in 61B) to include the @Override tag right on top of the method signature.
1 |
|
actually, the Override keyword is not needed. But it can be served as a checklist for us to debug.
Inheritance
Interface Inheritance
interface can also inheritance.
just have interface, no code!
Implementation Inheritance
with default method, we can write default method in interfaces
for SLList and AList, we write:
1 | default public void print() { |
However, the efficiency of the method in SLList and ‘AList’ differs.
For an SLList, the get method needs to jump through the entirety of the list. during each call. It’s much better to just print while jumping through!
for this, we need to override it:
1 |
|
when adding:
List61B<String> lst = new SLList<String>();
which print() to call?
the SLList.print() one
How do java know which print() to call?
dynamic method selection (DMS)
an object: compile-time type x
run-time type y
if y overrides the method, y’s method would be used instead.
without @Override, the default method in the interface would be excuted!
e.g.:
1 | public interface Animal { |
Another way to understand DMS
DMS as two-step process: compiling step & running step
Dynamic type of a is Dog. So use Dog’s praise(Animal)
important: “is-a” relationships are better than “has-a” relationships.
Extends
the extends keyword
class is a hyponym of an interface –> implements
class is a hyponym of another class –> extends
features
all methods from the superclass are contained
change the method in the superclass: @Override
you can also call the method in the superclass by super
constructor: must come first with super
1 | public VengefulSLList(Item x) { |
Java requires that all constructors must start with a call to one of its superclass’s constructors.
without super(x), you just get the default method!
The reason:
1 | public class Human {...} |
if run: TA Christine = new TA();
Then the TA would be human first, and then be TA!
Object class
every class was extended from the Object class
Encapsulation 封装
Core: hiding information from the outside
hiding information that others don’t need is another fundamental approach when managing a large system.
a module: a set of methods that work together as a whole to perform a task or set of related tasks
the private keyword: ensuring that the underlying complexity isn’t exposed to the outside world.
How Inheritance Breaks Encapsulation
example 1:
1 | public void bark() { |
example 2:
1 | public void bark() { |
it is basically the same without inheritance.
when overriding them:
1 |
|
Given a VerboseDog vd, what would vd.barkMany(3) output, given the first implementation above? The second implementation?
a: As a dog, I say: bark bark bark
b: bark bark bark
c: Something else
Actually, for example 1, the answer is A
for example 2, the answer is infinite loop.
Type Checking
For each line of code below, decide the following:
Does that line cause a compilation error?
Which method uses dynamic selection?

The lines: sl.printLostItems();
a compile-time error: the compiler determines whether something is valid based on the static type of the object. Since sl is of static type SLList, and printLostItems is not defined in the SLList class, the code will not be allowed to run
VengefulSLList<Integer> vsl2 = sl;
also a compile-time error(similar reason)
Like variables as seen above, expressions using the new keyword also have compile-time types.
SLList<Integer> sl = new VengefulSLList<Integer>();
compile-time type of right hand side: VengefulSLList
VengefulSLList<Integer> vsl = new SLList<Integer>();
compile-time type of right hand side: SLList
Casting
tell the compiler that the specific expression has a specific type
Poodle largerPoodle = (Poodle) maxDog(frank, frankJr); // compiles! Right hand side has compile-time type Poodle after casting
Caution: casting do not do its type-checking duties!
One possible error:
1 | Poodle frank = new Poodle("Frank", 5); |
Higher-order functions
in python:
1 | def tenX(x): |
In java:
1 | public interface IntUnaryFunction { |
when calling:
1 | System.out.println(do_twice(new TenX(), 2)); |
The new feature was added after Java8.
To notice: Java is mainly an OOP language, so that its implementation of Functional Programming is much limited!
Subtype Polymorphism
Java: how objects can have many forms or types
OOP: how an object can be regarded as an instance of its own class, an instance of its superclass, an instance of its superclass’s superclass, and so on.
for python comparison:
Explicit HoF Approach
1 | def print_larger(x, y, compare, stringify): |
Subtype Polymorphism Approach
1 | def print_larger(x, y): |
An example: Max function
debug the following program:
1 | public static Object max(Object[] items) { |
the error was items[i] > items[maxDex], in which the Object cannot be compared.
In python or C++, > operator can refer to different meanings when applied to different types of parameters.
In Java, however, the operator cannot be done like this.
Therefore, we can add a function like this:
1 | public static Dog maxDog(Dog[] dogs) { |
However, we have to rewrite the method for many other programs. Therefore, Instead, we turn to interface inheritance to help us out.
1 | public interface OurComparable { |
We will define its behavior like so:
Return -1 if this < o.
Return 0 if this equals o.
Return 1 if this > o.
The implementation of it in class of Dog:
1 | public int compareTo(Object o) { |
then, we can generalize the function in previous:
1 | public static OurComparable max(OurComparable[] items) { |
Benefits for it:
No need for maximization code in every class(i.e. no Dog.maxDog(Dog[]) function required
We have code that operates on multiple types (mostly) gracefully
Comparables
The interface OurComparable have some issues:
- Awkward casting to/from Objects
- No existing classes implement OurComparable (e.g. String, etc.)
- No existing classes use OurComparable (e.g. no built-in max function that uses OurComparable)
to fix them, we used the comparable interface that have been defined by Java.


comparator
an interface that looks very similar
inside:
1 | public interface Comparator<T> { |
The rule for compare is just like compareTo.
let’s give Dog class a NameComparator.
1 | import java.util.Comparator; |
The structure is:

summarize
Interfaces in Java give us the ability to make callbacks.
comparable: defines the natural ordering of a type (only one compareTo method can exist!)
comparator: a third-party machine that compares two objects to each other.
Multiple ways to compare –> comparator
