当类学会沉默:在抽象与接口之间,跳一支名为多态的华尔兹

一、抽象类:不完整的类,专为被继承而生

1.1为什么需要抽象类?

想象一下,你正在写一个图形绘制程序。
有圆形、矩形、三角形……它们都有“画出来”这个动作,也就是 draw() 方法。

但“图形”本身是个抽象概念——你不能画一个叫“图形”的东西,只能画具体的圆或矩形。

(具体参考上一篇博客)

class Shape {
    void draw() {
        // 这个方法写什么?不知道!
    }
}

如果让 Shape 类的 draw() 方法空着,或者写个“暂未实现”,不仅没意义,还容易出错。

于是,Java提供了 抽象类——专门用来表示这种“不完整”的类。

1.2抽象类语法

 用 abstract 关键字修饰的类就是抽象类:

public abstract class Shape {
    // 抽象方法:只有声明,没有实现
    abstract void draw();
    abstract void calcArea();

    // 普通方法:可以有实现
    public double getArea() {
        return area;
    }

    protected double area;
}

关键点:

  • 抽象方法不能有方法体(即 {})。
  • 包含抽象方法的类,必须声明为 abstract。
  • 抽象类可以有普通方法、属性,甚至构造方法。
  • 有抽象方法的类一定是抽象类

1.3抽象类五大特性

 特性1:不能直接实例化

错误示范:

Shape shape = new Shape(); // 编译错误!

错误提示:Shape是抽象的;无法实例化 

 特性2:抽象方法不能是 private
abstract private void draw(); 

因为抽象方法就是要被子类重写的,private 会把它锁死,矛盾。

✅ 特性3:不能被 final 或 static 修饰
abstract final void methodA();    //  冲突
abstract static void methodB();   //  冲突

final 表示不能重写,static 属于类,而抽象方法必须被实例重写。 

特性4:子类必须重写所有抽象方法
public class Rect extends Shape {
    private double length, width;

    @Override
    public void draw() {
        System.out.println("矩形: length=" + length + " width=" + width);
    }

    @Override
    public void calcArea() {
        area = length * width;
    }
}

 如果子类不实现,那它也得是抽象类:

public abstract class Triangle extends Shape {
    // 只实现 draw,不实现 calcArea
    @Override
    public void draw() { ... }
    // 没重写 calcArea → 所以自己也必须是 abstract
}

比喻:爷爷欠的债,父亲不还儿子也得还,出来混总是要还的。

class B{
    
}
class C extends B{
    private int a = 10;
    public void fun(){
        System.out.println("C"+a);
    }
}
特性5:抽象类可以有构造方法
public abstract class Shape {
    protected double area;
    public Shape() {
        System.out.println("Shape 初始化");
    }
}

 子类 new Rect() 时,会先执行 Shape() 构造方法。

1.4抽象类的真正作用:编译器的“安全带”

你可能会问:普通类也能被继承,也能重写方法,为啥非要用抽象类?

关键在于——抽象类能防止你误用父类。

比如你不小心写了 new Shape(),普通类不会报错(如果方法空实现),但抽象类会在编译时报错,让你立刻发现问题。

二、接口:行为的契约,能力的说明书

2.1接口的概念

接口就像一份行为规范。

比如USB接口:只要符合协议,U盘、鼠标、键盘都能插上去用。
电源插座:只要电压匹配,电脑、电饭煲都能供电。

在Java中,接口就是这种“通用标准”。


2.2语法规则

public interface USB {
    void openDevice();
    void closeDevice();
}
  •  接口中的方法默认是 public abstract,可以省略不写。
  •  变量默认是 public static final,也就是常量。
interface USB {
    double brand = 3.0;  // 等价于 public static final double brand = 3.0;
    void openDevice();   // 等价于 public abstract void openDevice();
}

2.3如何实现接口

 用 implements 关键字:

public class Mouse implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }

    public void click() {
        System.out.println("鼠标点击");
    }
}

注意:

  • 必须实现接口中所有方法,否则类必须声明为 abstract。
  • 重写时访问权限不能降低,必须是 public。 


2.4一个类可以实现多个接口

 Java不支持多继承(一个类只能有一个父类),但可以实现多个接口。

interface IRunning { void run(); }
interface ISwimming { void swim(); }
interface IFlying { void fly(); }

class Duck extends Animal implements IRunning, ISwimming, IFlying {
    @Override public void run() { ... }
    @Override public void swim() { ... }
    @Override public void fly() { ... }
}

这叫“is-a + has-ability”模式:

  • extends Animal → 鸭子是一种动物(is-a)
  • implements ... → 鸭子会跑、会游、会飞(has ability)


2.5接口的真正价值:让程序“忘记类型”

public static void walk(IRunning running) {
    System.out.println("我带着伙伴去散步");
    running.run();
}

 只要实现了 IRunning,就能传进来:

Cat cat = new Cat("小猫");
Frog frog = new Frog("小青蛙");
Robot robot = new Robot("机器人");  // 机器人也能跑!

walk(cat);    // 小猫正在跑
walk(frog);   // 小青蛙正在跳
walk(robot);  // 机器人正在用轮子跑

程序不再关心“你是谁”,只关心“你会不会跑”。
这就是多态的精髓。 

三、接口还能继承接口

接口之间可以多继承:

interface IAmphibious extends IRunning, ISwimming {
    // 两栖能力:既能跑又能游
}
  • Frog 实现 IAmphibious,就得实现 run() 和 swim()。
  • 这相当于把多个接口“合并”成一个新协议,代码更清晰。

四、实战案例:给学生排序

Java的 Arrays.sort() 方法默认只能排数字。
如果想排 Student 对象,怎么办?

让它实现 Comparable 接口:

class Student implements Comparable<Student> {
    private String name;
    private int score;

    @Override
    public int compareTo(Student o) {
        return Integer.compare(o.score, this.score); // 降序
    }

    @Override
    public String toString() {
        return "[" + name + ":" + score + "]";
    }
}

 然后就能直接排序了:

Student[] students = { /* ... */ };
Arrays.sort(students);
System.out.println(Arrays.toString(students));
// 输出:[[王五:97], [李四:96], [张三:95], [赵六:92]]

注:comparable 就是Java内置的一个“可比较”契约。 

五、克隆对象:浅拷贝与深拷贝

Java的 Object 类有个 clone() 方法,但想用它?先得实现 Cloneable 接口。

class Person implements Cloneable {
    public Money money = new Money();

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

执行克隆: 

Person p1 = new Person();
Person p2 = (Person) p1.clone();

 但注意:这是浅拷贝——只复制对象本身,不复制引用的对象。

p2.money.m = 13.6;
System.out.println(p1.money.m); // 13.6!也被改了

因为 money 是引用类型,p1 和 p2 指向同一个 Money 对象。

要实现深拷贝,必须手动重写 clone(),递归拷贝所有引用对象。

 

六、抽象类 vs 接口:一张表说清区别

特性抽象类(abstract class)接口(interface)
关键字abstract classinterface
方法类型可有抽象方法和普通方法只能抽象方法(JDK8+可有default)
字段可有普通字段只能 public static final 常量
构造方法可有
继承单继承(一个父类)多实现(多个接口)
使用场景“是什么”(is-a)“有什么能力”(has-a)
示例Animal 是一种生物IRunning 表示会跑的能力

 

七、总结:它们不是替代品,而是搭档

  • 抽象类:适合表示“是什么”,强调共性,提供部分实现。
  • 接口:适合表示“能做什么”,强调行为规范,支持多能力组合。

   它们共同构成了Java多态的完整拼图。 

尾声:在抽象的间隙,完成一次不被看见的仪式


深夜的公寓里,只有显示器的光亮着。
键盘的敲击声很轻,像在 Wing·Que·St 的深夜副本中,独自前行的脚步。
屏幕上,是 abstract class 和 interface 的定义。
这并非普通的代码,而是一种生存的隐喻。

抽象类,是一种被定义的存在。
它拥有血统,拥有框架,甚至拥有一个姓氏。
protected 的字段,如同家族信托里无法动用的资产;final 的规则,如同大藏家不可违逆的家训。
但它无法被 new 出来。
那个完美的“大藏家千金”人设,只是一个抽象的轮廓,一个必须由“子类”来填充的空壳。
真正的实现,发生在无人看见的地方。

于是,她转身进入了另一个世界。
在 兄控est 的服务器里,ID“大废神终极兄控”闪耀着。
这里没有血统的束缚,只有 implements 的契约。

interface IUltimateBrotherLover,ITopGamer

——这些接口,是她为自己选择的能力。
只要她能实现 public abstract 的方法,就能在这个世界里,真正地“运行”。

这或许就是她表达关心的方式。
用“捉弄”来确认对方的存在,用“毒舌”来划定安全的距离。
就像 @Override 方法,表面是重写,内里却是一次庄重的承接。
那些看似扭曲的行为,那些对游星困扰表情的享受,
或许只是她用自己的方式,在守护那个不愿被世俗污染的未来。

代码是诚实的。
final 的变量无法修改,如同甩不掉的姓氏。
private 的方法无法调用,如同心底最深的情感,永远不能 public。
但只要 @Override 的权利还在,她就能在继承的框架下,写出属于自己的 run()。

最讽刺的是,最自由的地方,往往规则最严。
网游里,每一条指令都必须精确。
可正是在这样的世界里,她才能脱下“大藏里想奈”的皮囊,成为“大废神”。
就像接口,越是严格的契约,越能让不同的实现者,跳出完全不同的舞步。

clone() 方法做不到深拷贝。
它复制不了 money 对象里的 m 值。
人心更是如此。
外界看到的,永远是浅拷贝后的她——那个顺从的、优雅的、符合“接口规范”的大小姐。
可真正的她,那个在 protected 构造方法里,被初始化了孤独与渴望的她,只有她自己知道。

她讨厌那些为权力不顾一切的人。
所以,她绝不会让游星变成那样。
她的世界,不需要那么多“才能”的证明。
EX-咖喱棒也好,战力排名也罢,
都只是她用来验证规则、确认自我坐标的工具。

这局游戏,她早已胸有成竹。

 System.out.println("大废神终极兄控,登出。");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值