CS61B笔记系列 8 Inheritance, Implements


8.1 Method Overloading in Java

JAVA 允许函数重载

PS:其实不算一节,但是可以引出下面的内容

但是重载有时候不够优雅:

  • Code is virtually identical. Aesthetically gross.
  • Harder to maintain.
    • Any change made to one ,must be made to another
    • Including bug fixe
  • Repeating youself
  • Won’t work for future lists. If we create a QList class, have to make a third method.

如何优雅的解决问题:使用 Inheritance 继承

8.2 Hypernyms, Hyponyms, and Interface Inheritance

开始要梳理两个词汇:

Hypernyms:上位词

Dog is a “hypernym” of poodle(卷毛犬,贵宾),malamute(爱斯基摩狗,雪橇犬),yorkie(约克夏,TBBT 里的小桂子).

Hyponyms : 下位词

Hypernyms / Hyponyms 是一个所谓的 “is-a” 关系

那么如何在 java 里体现以上的这样的关系:

https://raw.githubusercontent.com/biepin7/CloudForImg/master/20220321143228.png
  • Step 1: Define a reference type for our hypernym (List61B.java).
    • use interface instead of class
public interface List61B<Item> {
    public void insert(Item x, int position);
    public void addFirst(Item x);
    public void addLast(Item x);
    public Item getFirst();
    public Item getLast();
    public Item get(int i);
    public int size();
    public Item removeLast();
}
  • Idea: Interface is a specification of what a List is able to do, not how to do it.
  • Step 2: Specify that SLLists and ALists are hyponyms of that type.
    • Use the new implements keyword to tell the Java compiler that SLList and AList are hyponyms of List61B.
public class AList<Item> implements List61B<Item>{

8.3 Overriding vs. Overloading

要区分 OverridingOVerloading

  • 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.

PS:不是很难区分的概念

the @Override Annotation

使用 @Override 注解,帮助书写代码

Why use @Override?

  • Main reason: Protects against typos.
    • If you say @Override, but it the method isn’t actually overriding anything, you’ll get a compile error.
    • e.g. public void addLats(Item x)
  • Reminds programmer that method definition came from somewhere higher up in the inheritance hierarchy.

8.4 Interface Inheritance

https://raw.githubusercontent.com/biepin7/CloudForImg/master/20220321151222.png

8.5 Implementation Inheritance: Default Methods

总而言之:我就要在接口里写 how to do 的代码!

Use the default keyword to specify a method that subclasses should inherit from an interface.:

package lec8_inheritance1;

public interface List61B<Item> {
        public void insert(Item x, int position);
        public void addFirst(Item x);
        public void addLast(Item x);
        public Item getFirst();
        public Item getLast();
        public Item get(int i);
        public int size();
        public Item removeLast();

        **default public void print() {
            for (int i = 0; i < size(); i += 1) {
                System.out.print(get(i) + " ");
            }**
        }
}

当然这也引入了新的问题:比如对 SLList 来说, print() 方法就不那么高效。

所以为了防止有这样的情况发生:我们可以 Overriding Deafault Methods

public interface SLList<Item> implements {
   @Override
   public void print() {
      for (Node p = sentinel.next; p != null; p = p.next) {
             System.out.print(p.item + " ");       
       }

       System.out.println();
   }
}

8.6 Static and Dynamic Type, Dynamic Method Selection

本节讲了: “compile-time type” 和 “run-time type”的区别

Every variable in Java has a “compile-time type”, a.k.a. “static type”.

  • This is the type specified at declaration. Never changes!

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.

  • This is known as “dynamic method selection”.

8.7 Signature Selection,Dynamic Method Selection

做下面的题(坑非常多)

https://raw.githubusercontent.com/biepin7/CloudForImg/master/20220321170629.png
https://raw.githubusercontent.com/biepin7/CloudForImg/master/20220321171621.png
  • At compile time: We determine the signature S of the method to be called.
    • S is decided using ONLY static types.
https://raw.githubusercontent.com/biepin7/CloudForImg/master/20220321171903.png

• At runtime: The dynamic type of the invoking object uses its method with this exact signature S.

https://raw.githubusercontent.com/biepin7/CloudForImg/master/20220321172238.png

8.8 Interface vs. Implementation Inheritance

Interface Inheritance (a.k.a. what):

  • Allows you to generalize code in a powerful, simple way.

Implementation Inheritance (a.k.a. how):

  • Allows code-reuse: Subclasses can rely on superclasses or interfaces.
    • Example: print() implemented in List61B.java.
  • Gives another dimension of control to subclass designers: Can decide whether or not to override default implementations.

Important: In both cases, we specify “is-a” relationships, not “has-a”.

  • Good: Dog implements Animal, SLList implements List61B.
  • Bad: Cat implements Claw, Set implements SLList.

Particular Dangers of Implementation Inheritance

  • Makes it harder to keep track of where something was actually implemented (though a good IDE makes this better).
  • Rules for resolving conflicts can be arcane. Won’t cover in 61B.
    • Example: What if two interfaces both give conflicting default methods?
  • Encourages overly complex code (especially with novices).
    • Common mistake: Has-a vs. Is-a!
  • Breaks encapsulation!
    • What is encapsulation? See next week.

要区分好 “is a ” 和 “has a “的关系,防止代码的混乱

,

发表评论