知识回顾

本周核心概念:继承、多态、抽象类与接口

核心概念总结

继承与 super

  • 使用 extends 实现类继承
  • 子类继承父类的非私有属性和方法
  • super 关键字调用父类构造方法
  • Java 只支持单继承(一个子类一个父类)

方法重写与多态

  • 子类重写父类方法需使用 @Override
  • 方法签名必须相同(名称+参数列表)
  • 访问权限不能低于父类方法
  • 多态:父类引用指向子类对象

final 关键字

  • final 修饰类:不可被继承
  • final 修饰方法:不可被重写
  • final 修饰变量:常量,不可修改
  • final 变量命名规范:全大写+下划线

抽象类与接口

  • 抽象类:abstract class,可包含抽象方法
  • 接口:interface,所有方法默认 public abstract
  • 接口可以有默认方法(default)
  • 类可以实现多个接口但只能继承一个类

常见错误

  • 混淆 superthis 的使用场景
  • 重写方法时改变返回类型或访问权限
  • 试图实例化抽象类(new AbstractClass())
  • 混淆接口继承(extends)与类实现(implements)
  • 忘记调用父类构造方法(super())

选择题

选择最符合题意的答案(单选)

1. 关于Java继承,以下说法正确的是: 容易
  • A. 子类可以继承父类的非私有属性和方法
  • B. Java支持多重继承(一个子类多个父类)
  • C. 子类构造方法中不需要调用父类构造方法
  • D. private方法可以被继承和重写
显示答案与解析

正确答案:A

解析: Java只支持单继承(一个子类一个父类),子类构造方法中必须显式或隐式调用父类构造方法,private方法不能被继承和重写。

2. 以下代码的输出结果是什么? 中等
class Animal { void sound() { System.out.println("Animal makes sound"); } } class Dog extends Animal { @Override void sound() { System.out.println("Dog barks"); } void wagTail() { System.out.println("Dog wags tail"); } } public class Test { public static void main(String[] args) { Animal animal = new Dog(); animal.sound(); // animal.wagTail(); // 此行编译错误 } }
  • A. Animal makes sound
  • B. Dog barks
  • C. 编译错误
  • D. 运行时错误
显示答案与解析

正确答案:B

解析: 虽然animal声明为Animal类型,但实际指向Dog对象。调用sound()方法时发生多态,执行Dog类重写的方法。但wagTail()方法在Animal中不存在,所以编译错误(注释行)。

3. 关于final关键字,以下说法错误的是: 容易
  • A. final类不能被继承
  • B. final方法不能被重写
  • C. final变量可以在构造方法中多次赋值
  • D. final变量必须显式初始化
显示答案与解析

正确答案:C

解析: final变量只能赋值一次,可以在声明时初始化或在构造方法中初始化,但不能多次赋值。

4. 以下关于抽象类和接口的说法,正确的是: 中等
  • A. 抽象类可以有构造方法,接口不能有
  • B. 抽象类可以实现接口,接口不能继承类
  • C. 接口可以有成员变量,但必须是public static final
  • D. 以上都正确
显示答案与解析

正确答案:D

解析: 抽象类可以有构造方法(用于子类调用),接口不能有构造方法;抽象类可以实现接口,接口只能继承接口;接口中的变量默认是public static final。

代码分析题

分析代码,回答相关问题

5. 分析以下代码,回答问题: 困难
interface Flyable { int MAX_HEIGHT = 10000; // 接口常量 void fly(); default void land() { System.out.println("Landing..."); } } abstract class Bird implements Flyable { public Bird() { System.out.println("Bird constructor"); } public abstract void sing(); } class Sparrow extends Bird { public Sparrow() { super(); System.out.println("Sparrow constructor"); } @Override public void fly() { System.out.println("Sparrow flying at height: " + (MAX_HEIGHT - 5000)); } @Override public void sing() { System.out.println("Sparrow sings"); } @Override public void land() { System.out.println("Sparrow landing gracefully"); } } public class TestBirds { public static void main(String[] args) { Flyable sparrow = new Sparrow(); sparrow.fly(); sparrow.land(); // 调用sing方法需要向下转型 if (sparrow instanceof Sparrow) { ((Sparrow) sparrow).sing(); } } }
问题:
  • a) 解释接口中 MAX_HEIGHT 变量的特性
  • b) 分析 Sparrow 类中 land() 方法的注解 @Override 是否必要
  • c) 描述代码中的多态现象
  • d) 为什么在main方法中调用sing()需要向下转型?
显示答案与解析

参考答案:

a) MAX_HEIGHT 是接口中的常量,默认具有 public static final 特性,因此不可修改且可以通过接口名直接访问(Flyable.MAX_HEIGHT)。

b) @Override 不是必需的但推荐使用。它明确表示该方法重写了父类或接口中的方法,增加代码可读性,同时编译器会检查方法签名是否正确。

c) 多态现象:Flyable 接口引用 sparrow 指向 Sparrow 对象。调用 fly() 和 land() 方法时,实际执行的是 Sparrow 类中的实现,而不是接口中的默认实现。

d) sing() 方法定义在抽象类 Bird 中,而不是 Flyable 接口中。sparrow 声明为 Flyable 类型,只能访问接口中定义的方法。要访问 Bird 类中的 sing() 方法,需要向下转型为 Sparrow 或 Bird 类型。

编程题

根据要求编写Java代码

6. 形状计算系统 困难

任务要求

设计一个形状计算系统,要求:

  1. 定义抽象类 Shape,包含:
    • 抽象方法 double area() 计算面积
    • 抽象方法 double perimeter() 计算周长
    • final 方法 void display() 打印形状信息
  2. 创建 CircleRectangle 类继承 Shape
  3. 定义接口 Resizable,包含抽象方法 void resize(double factor)
  4. Circle 实现 Resizable 接口
  5. 编写测试类,创建各种形状并调用方法

具体要求:

  • Circle 类应有半径属性,实现面积和周长计算
  • Rectangle 类应有长和宽属性
  • resize() 方法按比例调整图形大小
  • display() 方法打印形状类型和尺寸信息
显示参考答案
// 抽象类 Shape abstract class Shape { // 抽象方法:计算面积 public abstract double area(); // 抽象方法:计算周长 public abstract double perimeter(); // final方法:显示形状信息 public final void display() { System.out.println("Shape: " + this.getClass().getSimpleName()); System.out.println("Area: " + area()); System.out.println("Perimeter: " + perimeter()); } } // 接口 Resizable interface Resizable { void resize(double factor); } // Circle 类 class Circle extends Shape implements Resizable { private double radius; public Circle(double radius) { this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; } @Override public double perimeter() { return 2 * Math.PI * radius; } @Override public void resize(double factor) { radius *= factor; } @Override public void display() { super.display(); System.out.println("Radius: " + radius); } } // Rectangle 类 class Rectangle extends Shape { private double length; private double width; public Rectangle(double length, double width) { this.length = length; this.width = width; } @Override public double area() { return length * width; } @Override public double perimeter() { return 2 * (length + width); } @Override public void display() { super.display(); System.out.println("Length: " + length + ", Width: " + width); } } // 测试类 public class ShapeTest { public static void main(String[] args) { Shape circle = new Circle(5.0); circle.display(); System.out.println("\nResizing circle..."); ((Resizable) circle).resize(1.5); circle.display(); Shape rectangle = new Rectangle(4.0, 6.0); rectangle.display(); } }

预期输出:

Shape: Circle
Area: 78.53981633974483
Perimeter: 31.41592653589793
Radius: 5.0

Resizing circle...
Shape: Circle
Area: 176.71458676442586
Perimeter: 47.12388980384689
Radius: 7.5

Shape: Rectangle
Area: 24.0
Perimeter: 20.0
Length: 4.0, Width: 6.0

测试完成!

检查你的答案,巩固本周学习内容

60%

继续努力,掌握面向对象的核心概念!

返回学习 查看详细解析