Loading

CS61B_Lecture9

扩展,类型转换和高阶函数

前言

implements关键字可以用来表示interface之间的关系(接口继承),而类和类之间的继承关系则需要extends来实现。

extends关键字(继承)

extends关键字可以在保持原有功能的同时让我们增加新功能,形成一个新的子类。

例如:

public class RotatingSLList<Item> extends SLList<Item>

这样RotatingSLList类会默认继承SLList的如下东西:

  • 所有公共的属性
  • 所有的公共方法
  • 所有的公共嵌套类

但是有一些东西是不会被继承的:

  • 类本身的构造函数
  • private的属性和方法

那应该如何进行初始化的时候拿到初始的属性呢?

我们可以使用super()函数来进行初始化使得其继承父类的private属性。

所有类的父类-Object

所有类都是Object类的后代。我们看以下示例:

public class Human {...}

public class TA extends Human {...}

TA显式的继承了Human,而Human则隐式的继承了Object父类。

具体继承了类似如下几个方法:

  • .equals(Object obj)
  • .hashCode()
  • toString()
  • ...

继承可能破坏封装

假设Dog类有如下两个方法:

public void bark() {
    System.out.println("bark");
}

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

我们还有另一个版本的实现方式:

public void bark() {
    barkMany(1);
}

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

看似使用的时候可能没有区别,但假如我们定义了一个它的子类并重写了这个方法:

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

那么这里两种实现方式的结果便会大相径庭。

第二种会先调用父类的bark()->然后会调用当前Override的barkMany(1);->然后又会调用bark,最后无限递归造成栈溢出错误。

动态类型和静态类型

静态类型是编译的时候被声明的类型,动态类型指的是实际引用的对象的类型。

类型转换的原则:子类可以转换父类,但父类不能转为子类。

高阶函数

我们在61A中学过了python的高阶函数:

def tenX(x):
    return 10*x

def do_twice(f, x):
    return f(f(x))

但Java的高阶函数应该怎么写呢?

java中不能直接传参函数,但我们可以利用接口继承。

我们先定义一个这样的类,里面有一个接受int返回int的函数声明:

public interface IntUnaryFunction {
    int apply(int x);
}

来实现以下这个函数:

public class TenX implements IntUnaryFunction {
    /* Returns ten times the argument. */
    public int apply(int x) {
        return 10 * x;
    }
}

接下来需要实现do_twice(f, x)

public static int do_twice(IntUnaryFunction f, int x) {
    return f.apply(f.apply(x));
}

调用类似于这样:

System.out.println(do_twice(new TenX(), 2));
posted @ 2025-12-26 14:30  幽暗天琴沙雕  阅读(4)  评论(0)    收藏  举报