![Thumbnail: java](https://i.loli.net/2021/10/04/hJaRBNOwYsVZ3M2.png)
CS61B_9
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.