跳到主要内容

Java 继承和多态

继承和多态是面向对象编程的核心特性。

继承

基本概念

继承允许创建一个类基于现有类,继承父类的属性和方法。

语法

// 父类
public class Animal {
public String name;
public int age;

public void eat() {
System.out.println("正在吃饭");
}

public void sleep() {
System.out.println("正在睡觉");
}
}

// 子类
public class Dog extends Animal {
public String breed;

// 子类特有方法
public void bark() {
System.out.println("汪汪叫");
}
}

使用继承

public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "旺财";
dog.breed = "金毛";

dog.eat(); // 继承的方法
dog.sleep(); // 继承的方法
dog.bark(); // 子类特有的方法
}
}

super 关键字

public class Animal {
public String name;

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

public class Dog extends Animal {
public String breed;

public Dog(String name, String breed) {
super(name); // 调用父类构造方法
this.breed = breed;
}
}

方法重写

子类可以重写父类的方法:

public class Animal {
public void eat() {
System.out.println("正在吃饭");
}
}

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

重写规则

  1. 方法名相同
  2. 参数列表相同
  3. 返回类型相同或兼容
  4. 访问权限不能比父类更严格

多态

同一接口,不同实现:

// 父类引用指向子类对象
Animal animal = new Dog();
animal.eat(); // 调用 Dog 的 eat 方法

向上转型和向下转型

// 向上转型(自动)
Animal animal = new Dog();

// 向下转型(需要强制转换)
Dog dog = (Dog) animal;

多态的应用

public class Animal {
public void speak() {
}
}

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

public class Cat extends Animal {
@Override
public void speak() {
System.out.println("喵喵");
}
}

public class Main {
public static void main(String[] args) {
Animal[] animals = {new Dog(), new Cat()};

for (Animal animal : animals) {
animal.speak(); // 多态调用
}
}
}

final 关键字

// final 类(不能被继承)
public final class String {
}

// final 方法(不能被重写)
public class Parent {
public final void method() {
}
}

// final 变量(常量)
public class Constants {
public static final double PI = 3.14159;
}

抽象类和抽象方法

抽象类

public abstract class Animal {
public String name;

// 抽象方法(没有方法体)
public abstract void speak();

// 普通方法
public void eat() {
System.out.println("正在吃饭");
}
}

实现抽象类

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

接口

定义接口

public interface Flyable {
// 接口中的方法默认是抽象的
void fly();

// 常量
int MAX_SPEED = 100;
}

实现接口

public class Bird implements Flyable {
@Override
public void fly() {
System.out.println("鸟儿在飞翔");
}
}

多实现

public interface Flyable {
void fly();
}

public interface Swimmable {
void swim();
}

public class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("鸭子在飞");
}

@Override
public void swim() {
System.out.println("鸭子在游泳");
}
}

接口的默认方法(Java 8+)

public interface Flyable {
void fly();

// 默认方法
default void display() {
System.out.println("这是一个飞行器");
}
}

接口的静态方法(Java 8+)

public interface Flyable {
static int getMaxSpeed() {
return 100;
}
}

接口的私有方法(Java 9+)

public interface Flyable {
default void display() {
printInfo();
}

private void printInfo() {
System.out.println("飞行器信息");
}
}

Object 类详解

在 Java 中,所有类都直接或间接继承自 java.lang.Object 类。Object 类是 Java 类层次结构的根类。

Object 类的方法

方法说明
toString()返回对象的字符串表示
equals(Object obj)判断两个对象是否相等
hashCode()返回对象的哈希码
getClass()返回对象的运行时类
clone()创建并返回对象的副本
finalize()垃圾回收时调用(已废弃)
notify()唤醒等待的线程
notifyAll()唤醒所有等待的线程
wait()让线程等待

toString() 方法

public class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

// 重写 toString 方法
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}

// 使用
Person p = new Person("张三", 20);
System.out.println(p); // 自动调用 toString()
// 输出: Person{name='张三', age=20}

// 不重写时的默认输出
// 输出: Person@15db9742(类名@哈希码)

equals() 和 hashCode()

import java.util.Objects;

public class Person {
private String name;
private int age;

// 重写 equals 方法
@Override
public boolean equals(Object obj) {
// 1. 检查是否是同一个对象
if (this == obj) return true;

// 2. 检查是否为 null 和类型
if (obj == null || getClass() != obj.getClass()) return false;

// 3. 类型转换并比较字段
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}

// 重写 hashCode 方法(equals 和 hashCode 必须同时重写)
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}

// 使用
Person p1 = new Person("张三", 20);
Person p2 = new Person("张三", 20);

System.out.println(p1 == p2); // false(不同对象)
System.out.println(p1.equals(p2)); // true(内容相同)

// hashCode 相同是 equals 为 true 的必要条件
System.out.println(p1.hashCode() == p2.hashCode()); // true

getClass() 方法

Person p = new Person("张三", 20);

// 获取运行时类
Class<?> clazz = p.getClass();
System.out.println(clazz.getName()); // "Person"
System.out.println(clazz.getSimpleName()); // "Person"

// 判断对象类型
if (p.getClass() == Person.class) {
System.out.println("是 Person 类");
}

// 使用 instanceof(推荐)
if (p instanceof Person) {
System.out.println("是 Person 实例");
}

// Java 16+ 模式匹配
if (p instanceof Person person) {
System.out.println(person.getName());
}

clone() 方法

// 要使用 clone(),类必须实现 Cloneable 接口
public class Person implements Cloneable {
private String name;
private int age;

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

// 使用
Person p1 = new Person("张三", 20);
Person p2 = (Person) p1.clone();

System.out.println(p1 == p2); // false(不同对象)
System.out.println(p1.equals(p2)); // true(内容相同)

方法重写 vs 方法隐藏

方法重写(Override)

实例方法可以被重写,运行时根据实际对象类型调用:

class Parent {
public void show() {
System.out.println("Parent show");
}
}

class Child extends Parent {
@Override
public void show() {
System.out.println("Child show");
}
}

Parent p = new Child();
p.show(); // "Child show"(多态)

方法隐藏(Hide)

静态方法不能被重写,只能被隐藏:

class Parent {
public static void show() {
System.out.println("Parent static show");
}
}

class Child extends Parent {
// 这是方法隐藏,不是重写!
public static void show() {
System.out.println("Child static show");
}
}

Parent p = new Child();
p.show(); // "Parent static show"(根据引用类型)

Child c = new Child();
c.show(); // "Child static show"

字段隐藏

字段也不能被重写,只能被隐藏:

class Parent {
public String name = "Parent";
}

class Child extends Parent {
public String name = "Child"; // 字段隐藏
}

Parent p = new Child();
System.out.println(p.name); // "Parent"(字段没有多态)

Child c = new Child();
System.out.println(c.name); // "Child"

重写 vs 隐藏对比

特性重写(Override)隐藏(Hide)
适用对象实例方法静态方法、字段
多态
运行时行为根据实际对象类型根据引用类型
@Override 注解可以使用不能使用

对象类型判断

instanceof 运算符

// 基本用法
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}

// Java 16+ 模式匹配
if (obj instanceof String s) {
System.out.println(s.length());
}

// 类型判断链
if (obj instanceof String s) {
System.out.println("字符串: " + s);
} else if (obj instanceof Integer i) {
System.out.println("整数: " + i);
} else if (obj instanceof Double d) {
System.out.println("浮点数: " + d);
} else {
System.out.println("未知类型");
}

getClass() vs instanceof

class Animal {}
class Dog extends Animal {}

Animal animal = new Dog();

// instanceof:判断是否是某个类或其子类的实例
System.out.println(animal instanceof Animal); // true
System.out.println(animal instanceof Dog); // true

// getClass():精确判断类型
System.out.println(animal.getClass() == Animal.class); // false
System.out.println(animal.getClass() == Dog.class); // true

继承的注意事项

1. 构造方法不能被继承

class Parent {
public Parent(String name) {
// ...
}
}

class Child extends Parent {
public Child() {
super("default"); // 必须显式调用父类构造方法
}

// 不能这样写:
// Child(String name) = Parent(name); // 错误!
}

2. 私有成员不能直接访问

class Parent {
private String secret = "密码";
}

class Child extends Parent {
public void show() {
// System.out.println(secret); // 错误!无法访问私有成员

// 只能通过父类提供的公共方法访问
// System.out.println(getSecret()); // 如果父类有 getter
}
}

3. 访问权限规则

重写方法的访问权限不能比父类更严格:

class Parent {
public void method() {}
protected void doSomething() {}
}

class Child extends Parent {
@Override
public void method() {} // OK:public -> public

// @Override
// private void doSomething() {} // 错误!不能更严格

@Override
public void doSomething() {} // OK:protected -> public(更宽松)
}

4. 异常抛出规则

重写方法不能抛出更宽泛的受检异常:

class Parent {
public void method() throws IOException {}
}

class Child extends Parent {
@Override
public void method() throws FileNotFoundException {} // OK:子类异常

// @Override
// public void method() throws Exception {} // 错误:更宽泛的异常

@Override
public void method() {} // OK:不抛出异常
}

小结

本章我们学习了:

  1. 继承的基本概念
  2. super 关键字的使用
  3. 方法重写
  4. 多态
  5. 向上转型和向下转型
  6. final 关键字
  7. 抽象类和抽象方法
  8. 接口和多实现
  9. 接口的默认方法、静态方法和私有方法
  10. Object 类详解(toString、equals、hashCode、getClass、clone)
  11. 方法重写 vs 方法隐藏
  12. 字段隐藏
  13. 对象类型判断(instanceof、getClass)
  14. 继承的注意事项

练习

  1. 创建一个图形类层次结构(父类 Shape,子类 Circle、Rectangle)
  2. 创建一个动物类层次结构,实现多态
  3. 创建一个实现了多个接口的类
  4. 使用抽象类实现一个支付系统
  5. 重写 Person 类的 toString、equals 和 hashCode 方法
  6. 演示方法隐藏和方法重写的区别
  7. 使用 instanceof 模式匹配处理不同类型的对象