Thumbnail: java

CS61B_9

by on under Java
5 minute read

Extends

类继承

if you want one class to be a hyponym of another class (instead of interface), you use extends.

类似 C++,子类会继承父类的所有 public member

Because of extends, RotatingSLList inherits all members of SLList:

  • All instance and static variables.
  • All methods.
  • All nested classes.

private members are inaccessible, Constructors are not inherited.

子类可以通过 super 关键字调用父类的函数,当该函数在子类中被重写时可通过这种方法调用。java 不允许通过 super.super. 的方式去调用爷爷辈的函数,因为这样会破坏封装 (encapsulation)

@Override
public Item removeLast() {
       Item oldBack = super.removeLast(); // calls Superclass’s version of removeLast()
       deletedItems.addLast(oldBack);
       return oldBack;
}

虽然构造函数不会被继承,但是一个类对象的构建是从最初的类开始的,也就是说,会先调用父类构造函数,再调用子类构造函数。
你可以手动调用父类构造函数,如果不手动调用的话会自动调用父类的默认构造函数,没有办法传参,手动调用的父类构造函数可以传参

public VengefulSLList(Item x) {
   super(x); // Calls SLList(Item x)
   deletedItems = new SLList<Item>();
}

public VengefulSLList(Item x) {
    /** 
     * Calls super(); 
     * which is SLList();
     * 对于链表来说,显然是个灾难
     */
   deletedItems = new SLList<Item>();
}

java 中的所有类都是 Object 类的子孙类,(Like UObject in Unreal)

As it happens, every type in Java is a descendant of the Object class.



Implementation Inheritance Breaks Encapsulation


继承会破坏封装,这里用课件上的两个例子吧

/** class Dog */
public void bark() {
   System.out.println("bark");
}

public void barkMany(int N) {
    for (int i = 0; i < N; i += 1) {
        bark();  
    }
}


/** A subclass of dog called verboseDog */
@Override
public void barkMany(int N) {
    System.out.println("As a dog, I say: ");
    for (int i = 0; i < N; i += 1) {
        bark();
    }
}

/** assuming vd is a Verbose Dog */

vd.barkMany(3); // output is: "As a dog, I say: bark bark bark"

/** class Dog */
public void bark() {
    barkMany(1);
}

public void barkMany(int N) {
    for (int i = 0; i < N; i += 1) {
        System.out.println("bark");  
    }
}

/** A subclass of dog called verboseDog */
@Override
public void barkMany(int N) {
    System.out.println("As a dog, I say: ");
    for (int i = 0; i < N; i += 1) {
        bark();
    }
}

/** assuming vd is a Verbose Dog */
vd.barkMany(3); 
/* the out put is: As a dog, I say: As a dog, I say: As a dog, I say: As a dog, I say: As a dog, I say:.......... then crashed */

所以说在接口设计上要很谨慎。



Type Checking and Casting

父类的静态类型引用可以动态指向子类的对象,但是只能调用父类已有的函数及其重写版本。
子类不能直接指向父类,就好比边牧一定是狗,所以 Dog d = new bianMuDog(); 是合法的,但是狗不一定是边牧,所以bianMuDog d = new Dog(); 是非法的。


Dynamic Method Selection and Casting Puzzle

直接上例子

public class Bird {
    public void gulgate(Bird b) {
        System.out.println("BiGulBi"); 
    }
}

public class Falcon extends Bird {
    public void gulgate(Falcon f) {
        System.out.println("FaGulFa");
    }
}

Bird bird = new Falcon();
Falcon falcon = (Falcon) bird;

bird.gulgate(falcon); // output is: BiGulBi
falcon.gulgate(falcon); // output is: FaGulFa

casting 对 variable 与被指向的 object 均不产生影响

Casting causes no change to the bird variable, nor to the object the bird variable points at!



Higher Order Functions

感觉有点类似于函数指针啥的(学艺不精)

/** An interface */
public interface IntUnaryFunction {
    int apply(int x);
}

/** Implementation of interface */
public class TenX implements IntUnaryFunction {
    public int apply(int x) {
        return 10 * x;
    }
}

/** TenX(TenX(2)) which is 2 * 10 * 10 = 200 */
public class HoFDemo {
    public static int do_twice(IntUnaryFunction f, int x) {
        return f.apply(f.apply(x));
    }
    public static void main(String[] args) {
        System.out.println(do_twice(new TenX(), 2));
    }
}

That’s it.

java