跳到主要内容Java 面向对象核心:继承、多态与抽象类接口 | 极客日志Javajava
Java 面向对象核心:继承、多态与抽象类接口
综述由AI生成Java 面向对象核心:继承、多态与抽象类接口。详细讲解了 Java 继承机制,包括单继承原则、成员变量与方法查找顺序、构造方法调用及方法重写。介绍了多态的实现方式(父类引用指向子类对象)、编译期与运行期绑定规则以及类型转换。同时阐述了抽象类与接口的区别、使用场景及规范,并讲解了四种内部类(成员、静态、局部、匿名)的定义、创建方式与实际应用场景,如事件监听器与隐藏实现细节。
花里胡哨30 浏览 继承的概念

继承的概念与示例

继承的两个特点
Java 中的继承有别于 C++,不能多继承,只能单继承,但是可以多层继承。
比如有三个类 A、B 和 C:一个子类只能继承一个父类,如 A 继承 B,不能同时继承多个父类,A 不能同时继承 B 和 C,但是可以 A 继承 B,然后 B 继承 C。
第二个特点是,假如一个 class 没有设置父类,那么默认继承 Object 类。

继承中成员变量的查找顺序


继承成员方法
关于子类中方法的重写:
父类如下:

子类 call 方法重写如下:

继承中的构造方法

访问权限修饰符
多态
1. Fu.java (父类)
package com.itheima.test2;
public class Fu {
String name = "Fu";
public void fuShow() {
System.out.println("父类的 fuShow 方法被调用了~");
}
public void show() {
System.out.println("父类的 show 方法被调用了~");
}
}
2. Zi.java (子类)
package com.itheima.test2;
public class Zi extends Fu {
String name = "Zi";
public void ziShow() {
System.out.println("子类的 ziShow 方法被调用了~");
}
@Override
public void show() {
System.out.println("子类重写的 show 方法被调用了~");
}
}
3. Test.java (测试类)
package com.itheima.test2;
public class Test {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.name);
f.show();
}
}
代码运行结果:
核心知识点总结(看图中的注释):
- 成员变量:编译看左边,运行也看左边(编译期绑定)。
f是 Fu 类型,所以 f.name 永远取 Fu 里的值。
- 成员方法:编译看左边,运行看右边(运行期绑定/动态绑定)。
f 是 Fu 类型,编译器允许调用 Fu 里的方法。
- 但运行时发现
f 实际上是 Zi 对象,所以执行的是 Zi 里重写的方法。
- 子类特有方法:不能通过父类引用直接调用。
f.ziShow() 会报错,因为父类 Fu 不知道子类有这个方法。
因此多态是有弊端的,为了解决这个弊端可以使用类型转换。
类型转换
抽象类和抽象方法
- 抽象方法:只有方法声明,没有方法体的方法
- 抽象类:包含抽象方法的类
(1)简单代码示例
public abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public abstract void makeSound();
public void eat() {
System.out.println(name + "正在吃东西");
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + "汪汪叫!");
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + "喵喵叫!");
}
}
public class Test {
public static void main(String[] args) {
Animal dog = new Dog("小狗");
Animal cat = new Cat("小猫");
dog.eat();
dog.makeSound();
cat.eat();
cat.makeSound();
}
}
(2)核心规则总结
抽象方法:使用 abstract 关键字没有方法体(没有 {})以分号结束
抽象类:使用 abstract 关键字可以有抽象方法(必须用 abstract)也可以有普通方法(可以有方法体),可以有属性,可以有构造方法
子类的责任:如果一个类继承了抽象类必须实现父类的所有抽象方法或者自己也声明为抽象类
不能创建对象:抽象类不能直接 new,只能通过子类来创建对象
(3)和普通类的区别
| 区别点 | 普通类 | 抽象类 |
|---|
| 创建对象 | ✅ 可以 | ❌ 不可以 |
| 抽象方法 | ❌ 不能有 | ✅ 可以有 |
| abstract 关键字 | ❌ 不需要 | ✅ 必须用 |
| 继承 | 可以选择 | 必须被子类实现 |
(4)为什么要用抽象类?
- 强制规范:要求子类必须实现某些方法
- 代码复用:抽象类中的普通方法可以被所有子类共享
- 设计约束:比如'动物'都要会叫,但'狗'和'猫'叫的方式不同
(5)一句话理解抽象类:
'半成品' 或 '模板',它定义了一部分功能,剩下的让子类去完成。
接口
(1)接口 vs 抽象类主要区别总结
| 特性 | 抽象类 | 接口 |
|---|
| 关键字 | abstract class | interface |
| 继承 | 只能继承一个 | 可以实现多个 |
| 方法 | 可以有抽象方法和普通方法 | 主要是抽象方法(新版可以有默认方法) |
| 变量 | 可以有各种变量 | 只能是常量(public static final) |
| 构造方法 | ✅ 可以有 | ❌ 不能有 |
| 单继承 | ✅ 只能继承一个类 | ✅ 可以实现多个接口 |
(2)使用场景简单例子
一句话记住接口:接口就是'约定'或'协议',它说:'只要你实现了我的方法,你就具备了某种能力'
比如:USB 接口约定好'连接'和'传输'两个方法,鼠标和键盘只要实现这两个方法,就能当 USB 设备用。
内部类
(1)例子
Outer.java(外部类)
public class Outer {
private String outerField = "我是外部类";
class Inner {
private String innerField = "我是内部类";
public void show() {
System.out.println("访问外部类:" + outerField);
System.out.println("访问内部类:" + innerField);
}
}
public void test() {
Inner inner = new Inner();
inner.show();
}
}
Test.java(测试类)
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.show();
outer.test();
}
}
(2)四种内部类
public class FourTypes {
private String name = "外部类";
class MemberInner {
void show() {
System.out.println("成员内部类:" + name);
}
}
static class StaticInner {
void show() {
System.out.println("静态内部类");
}
}
public void test() {
class LocalInner {
void show() {
System.out.println("局部内部类:" + name);
}
}
LocalInner li = new LocalInner();
li.show();
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类:" + name);
}
};
r.run();
}
}
(3)常用场景示例
情况 1:成员内部类(标准写法)
class Car {
private String brand = "奔驰";
class Engine {
private String type = "V8";
public void start() {
System.out.println(brand + "汽车的" + type + "发动机启动了!");
}
}
}
public class Test1 {
public static void main(String[] args) {
Car car = new Car();
Car.Engine engine = car.new Engine();
engine.start();
}
}
情况 2:静态内部类(独立性强)
class School {
private static String schoolName = "清华";
static class Student {
private String name;
public Student(String name) {
this.name = name;
}
public void study() {
System.out.println(name + "在" + schoolName + "学习");
}
}
}
public class Test2 {
public static void main(String[] args) {
School.Student student = new School.Student("小明");
student.study();
}
}
情况 3:匿名内部类(最常用)
public class Test3 {
public static void main(String[] args) {
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类:执行任务");
}
};
task.run();
Animal cat = new Animal() {
@Override
void sound() {
System.out.println("喵喵叫");
}
};
cat.sound();
}
}
abstract class Animal {
abstract void sound();
}
情况 4:局部内部类(方法里使用)
public class Test4 {
public void outerMethod() {
final int localVar = 100;
class LocalClass {
void show() {
System.out.println("局部内部类,访问局部变量:" + localVar);
}
}
LocalClass lc = new LocalClass();
lc.show();
}
public static void main(String[] args) {
Test4 test = new Test4();
test.outerMethod();
}
}
(4)实际应用场景
场景 1:简化代码(事件监听器)
class Button {
interface OnClickListener {
void onClick();
}
private OnClickListener listener;
public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
public void click() {
if (listener != null) {
listener.onClick();
}
}
}
public class App {
public static void main(String[] args) {
Button button = new Button();
button.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick() {
System.out.println("按钮被点击了!");
}
});
button.click();
}
}
场景 2:私有内部类(隐藏实现细节)
class Computer {
private class USBImpl implements USB {
@Override
public void connect() {
System.out.println("USB 已连接");
}
@Override
public void transfer() {
System.out.println("数据传输中...");
}
}
public USB getUSB() {
return new USBImpl();
}
}
interface USB {
void connect();
void transfer();
}
public class User {
public static void main(String[] args) {
Computer computer = new Computer();
USB usb = computer.getUSB();
usb.connect();
usb.transfer();
}
}
注意事项
- 成员内部类:需要外部类对象才能创建
- 静态内部类:可以直接创建,不需要外部类对象
- 匿名内部类:必须继承一个类或实现一个接口
- 局部内部类:只能在方法内部使用
内部类就是'包在里面的小助手',可以直接访问主人的私有东西,但对外界是隐藏的。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online