java 4继承

如何使用继承

java 复制代码
public class 子类名 extends 父类名 {
}

先用一个例子理解

java 复制代码
class Animal {
    void eat() {
        System.out.println("动物在吃东西");
    }
}

class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("狗在吃骨头");
    }

    void bark() {
        System.out.println("狗在叫");
    }
}

1. 什么是"父类引用指向子类对象"?

java 复制代码
Animal a = new Dog();

这里:

  • new Dog():真正创建的是一个 Dog 对象;
  • Animal a:这个变量的类型是 Animal;
  • 所以 a 是一个 父类类型的引用,指向子类对象。

这就像说:

这只动物其实是一条狗,但我现在只把它当作"动物"来看待。

2. 为什么不能直接调用子类特有方法?

java 复制代码
a.eat();   // 可以
a.bark();  // 编译报错

因为编译器看的是 a 的声明类型,也就是 Animal。

Animal 里没有 bark(),所以编译器会认为这个方法不存在。

虽然运行时 a 指向的是 Dog,但编译器不会自动去查子类有没有额外方法。

3. 强制类型转换是什么意思?

java 复制代码
Dog d = (Dog) a;
d.bark();  // 可以调用

(Dog) a 就是 强制类型转换 ,也叫 向下转型。

意思是:

我知道 a 虽然声明成 Animal,但它实际指向的是一个 Dog,现在请把它当成 Dog 来用。

转成 Dog 之后,就可以调用 Dog 特有的 bark() 方法了。

4. 为什么要"强制"?

因为从父类类型转回子类类型,不一定安全。

比如下面这种就会报错:

java 复制代码
Animal a = new Animal();
Dog d = (Dog) a; // 运行时报 ClassCastException

这里 a 实际指向的是 Animal,不是 Dog,所以不能转成 Dog。

5. 比较安全的写法

转换前先用 instanceof 判断一下:

java 复制代码
if (a instanceof Dog) {
    Dog d = (Dog) a;
    d.bark();
}

这样只有当 a 真正指向的是 Dog 时,才会转换,避免 ClassCastException。

简单记忆

操作 写法 说明
向上转型 Animal a = new Dog(); 自动转换,安全,但只能调用父类声明的方法
向下转型 Dog d = (Dog) a; 强制转换,可以调用子类特有方法,但可能出错
安全判断 a instanceof Dog 先判断再转,更安全

所以,"如果一个对象赋值给其父类的引用,此时想要调用该对象特有的方法,必须进行强制类型转换"的意思就是:

父类引用会"遮住"子类特有的方法。想调用这些特有方法,就必须把它强制转回子类类型。


override 是什么?

override 叫"方法重写",意思是:

子类重新定义父类里已经有的方法。

基本写法

java 复制代码
class Animal {
    void speak() {
        System.out.println("动物在叫");
    }
}

class Dog extends Animal {
    @Override
    void speak() {
        System.out.println("狗在汪汪叫");
    }
}

这里:

  • Animal 里有 speak();
  • Dog 继承 Animal;
  • Dog 里又写了一个同样的 speak();
  • 这就是 重写。

@Override 是一个注解,用来告诉编译器:

这个方法是在重写父类的方法。

它不是必须的,但 强烈建议写,因为如果你写错了方法名、参数,编译器会提醒你。

怎么调用?

java 复制代码
Animal a = new Dog();
a.speak();  // 输出:狗在汪汪叫

虽然 a 的类型是 Animal,但它实际指向的是 Dog 对象,所以会调用 Dog 里重写后的 speak()。

这就是多态。

重写的要求

子类重写父类方法时,要注意:

要求 说明
方法名必须相同 比如都是 speak
参数列表必须相同 参数类型、个数、顺序都要一样
返回值类型一般相同 或兼容的子类型
访问权限不能更严格 父类是 public,子类不能改成 private
不能重写 static 方法 static 方法属于类,不属于对象
不能重写 private 方法 子类根本看不到父类的 private 方法

重写和重载的区别

很多人会混淆这两个:

对比 重写 override 重载 overload
发生位置 子类和父类之间 同一个类里
方法名 相同 相同
参数列表 必须相同 必须不同
作用 改变父类方法的行为 提供多个同名方法

例如:

java 复制代码
class Calculator {
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }
}

这是 重载 overload,不是重写。

简单记忆

  • override:子类把父类的方法"换一种实现";
  • @Override:写在方法上面,表示"我在重写父类方法";
  • 调用时看 实际对象类型,不是看引用类型。

super 就是 "去父类那里找东西" 。

子类继承父类后,如果子类自己也有同名的方法、变量,或者想调用父类的构造方法,就可以用 super 明确指定:我要用父类的那个版本。

1. 调用父类构造方法:super(...)

java 复制代码
class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    Dog(String name) {
        super(name); // 调用父类 Animal(String name) 构造方法
    }
}

注意:

  • super(...) 必须写在子类构造方法的 第一行;
  • 如果子类构造方法里没有写 super(...),Java 会默认调用父类的 无参构造方法;
  • 如果父类没有无参构造方法,子类就必须显式写 super(...)。

2. 访问父类成员变量:super.变量名

java 复制代码
class Father {
    String name = "爸爸";
}

class Son extends Father {
    String name = "儿子";

    void show() {
        System.out.println(name);       // 儿子
        System.out.println(super.name); // 爸爸
    }
}

当子类和父类有同名变量时,直接写 name 会访问子类自己的;写 super.name 才能访问父类的。

3. 调用父类方法:super.方法名()

java 复制代码
class Animal {
    void speak() {
        System.out.println("动物在叫");
    }
}

class Dog extends Animal {
    @Override
    void speak() {
        super.speak(); // 先执行父类版本
        System.out.println("狗在汪汪叫");
    }
}

调用时:

java 复制代码
Dog dog = new Dog();
dog.speak();

输出:

text 复制代码
动物在叫
狗在汪汪叫

这里 super.speak() 就是:虽然子类重写了 speak(),但我还想保留父类原来的行为。

和 this 对比一下

关键字 含义 常见用法
this 当前对象自己 this.name、this() 调用本类构造
super 当前对象的父类部分 super.name、super() 调用父类构造、super.method() 调用父类方法

可以这样记:

  • this:找 自己;
  • super:找 父类。

常见错误

java 复制代码
class Dog extends Animal {
    Dog(String name) {
        System.out.println("准备创建狗");
        super(name); // 错误:super() 必须在第一行
    }
}

还有,super 不能在 static 方法里使用,因为静态方法不属于某个对象。

一句话总结

super 就是让子类在需要时能访问父类的构造方法、变量和方法,尤其是 子类重写或隐藏了父类内容时,用 super 找回父类版本。


不完全一样,它们有重叠,但不是同一个东西。

可以这么理解:

对比点 Java final C++ const
修饰变量 表示只能赋值一次,之后不能重新赋值 表示变量是只读的,不能修改
修饰对象/引用 final 只保证引用不变,对象内部仍可改 const 可以限制对象本身不能被修改
修饰方法 final 表示方法不能被重写 const 放在成员函数后面,表示该方法不会修改对象
修饰类 final 表示类不能被继承 const 不能用来修饰类
修饰指针/引用 Java 没有指针,所以没有这种用法 const 可以修饰指针本身或指针指向的内容

变量层面:最像

java 复制代码
final int x = 10;
x = 20; // 报错
cpp 复制代码
const int x = 10;
x = 20; // 报错

这里它们很像,都是"初始化后不能改"。

但对象层面差别很大

Java 里:

java 复制代码
final List<String> list = new ArrayList<>();
list.add("hello"); // 可以
list = new ArrayList<>(); // 不行

final 只是说 list 这个引用不能指向别的对象,但对象里面的内容可以改。

C++ 里:

cpp 复制代码
const MyClass obj;
obj.modify(); // 如果 modify 不是 const 成员函数,会报错

const 能限制对象本身不能被修改,这是 Java final 做不到的。

修饰方法时也不一样

Java:

java 复制代码
public final void show() { }

表示子类不能重写这个方法。

C++:

cpp 复制代码
void show() const { }

表示这个成员函数不会修改当前对象。

简单记

  • Java final:不能重新赋值、不能重写、不能继承。
  • C++ const:强调"只读",能修饰变量、指针、引用、对象和成员函数。
  • Java 的 const:只是保留关键字,目前没用。

所以如果你是在学 Java,看到 final 不要直接把它当成 C++ 的 const,变量上有点像,但对象和方法上的语义差别挺大。

相关推荐
aqiu1111112 小时前
【C++算法打怪专栏】C++ `unordered_set` 常用初始化与插入方法总结
开发语言·c++·算法
众链网络2 小时前
Agent 的成本大头不在“写“,在“判断“:拆解专用决策模型的三层架构
java·开发语言·人工智能·微服务
周小董2 小时前
[1371]jdk管理工具
java·开发语言
Terra.K2 小时前
高精度阶乘求和模板深度解析
开发语言·c++·算法
Hum8le2 小时前
漏洞知识点《php伪协议》
开发语言·安全·web安全·php
青春逝如流水2 小时前
Java 中线程的创建方式:从基础到现代
java·开发语言·多线程·ai文章
智码看视界2 小时前
C++智能指针全景剖析及面试20问
开发语言·c++·深度学习·面试·内存管理·智能指针
铅笔小新z3 小时前
【C语言】深入理解指针
c语言·开发语言
Peregrine93 小时前
C++ - > 类和对象
java·c++·算法