0

0

Java类设计与继承结构的最佳实践

P粉602998670

P粉602998670

发布时间:2026-01-12 16:34:03

|

771人浏览过

|

来源于php中文网

原创

子类不该覆盖父类的public方法,除非明确设计为可重写;应优先用组合代替继承,避免构造器中调用可重写方法,并根据是否需共享状态选择接口或抽象类。

java类设计与继承结构的最佳实践

子类不该覆盖父类的 public 方法,除非明确设计为可重写

Java 中 public 方法默认是“开放扩展点”,但多数业务类并非为继承而设计。如果父类没用 @Override 注解标记、也没在 Javadoc 里写明“此方法可被子类重写”,那它大概率不是契约的一部分。

常见错误现象:NullPointerException 出现在子类重写的 toString() 里,只因父类构造器中调用了该方法(此时子类字段尚未初始化);或重写 hashCode() 却没同步改 equals(),导致 HashSet 行为异常。

  • 判断依据:看父类是否声明了 final,或是否在构造器中调用该方法
  • 安全做法:把可重写的方法显式标为 protected,或加 @Override + 完整 Javadoc 说明契约
  • IDE 提示不等于安全——IntelliJ 默认允许重写 public 方法,但 javac 不校验语义合理性

用组合代替继承,尤其当“is-a”关系不稳固时

比如 Employee 类继承 Person 看似合理,但一旦业务要求“兼职学生员工”同时有 StudentEmployee 属性,单继承立刻失效。这时 Employee 应持有 Person 实例,而非继承它。

使用场景:需要复用逻辑但又不想暴露父类接口、需运行时切换行为(如策略模式)、或父类来自第三方 SDK(无法修改)。

立即学习Java免费学习笔记(深入)”;

ClipDrop Relight
ClipDrop Relight

ClipDrop推出的AI图片图像打光工具

下载
  • 组合的关键是把依赖声明为 private final Person person;,而非 extends Person
  • 不要为了“少写几行代码”而选继承——多写几个委托方法(getName() { return person.getName(); })换来的是长期可维护性
  • 注意 Liskov 替换原则失效的信号:子类必须重写父类某个方法才能让逻辑正确,这往往意味着继承关系建模错误

抽象类 vs 接口:优先选接口,除非需要共享状态或默认实现逻辑

Java 8+ 允许接口含 default 方法,但接口仍不能定义实例字段。如果多个子类必须共用一个 private int retryCount; 或缓存 Map,抽象类更合适;否则一律用接口。

参数差异:interface 支持多实现,abstract class 只能单继承;接口方法默认 public abstract,抽象类方法可设 protected 或包私有。

  • 性能影响极小,但接口更利于 mock 测试(无需构造抽象类实例)
  • 避免在接口里塞太多 default 方法——它容易演变成“伪抽象类”,破坏接口的契约纯粹性
  • 如果已有抽象类且新增功能只需默认实现,别急着改成接口:迁移成本(所有实现类要改 implementsextends)可能远超收益

构造器中禁止调用可被重写的方法

这是 Java 继承中最隐蔽的陷阱。父类构造器执行时,子类字段还未初始化,此时若调用被子类重写的方法,会访问到未初始化的字段,结果是 null0,且无编译警告。

public class Parent {
    public Parent() {
        init(); // 危险!子类可能重写了 init()
    }
    public void init() { /* do something */ }
}

public class Child extends Parent { private String data = "ready"; @Override public void init() { System.out.println(data.length()); // NullPointerException! } }

  • 修复方式:把 init() 改成 privatefinal,或拆出静态工厂方法分两步构造
  • IDEA 能检测此类问题(提示 “Call to possibly-overridden method in constructor”),但 Eclipse 默认不启用
  • Spring 的 @PostConstruct 就是为绕过这个限制而生——它在对象完全构造后才回调,但仅适用于受容器管理的 Bean

真正难的不是写出能跑的继承结构,而是每次加一个 extends 前,能意识到自己正在给未来埋下多少不可测的耦合点。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

831

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

737

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

733

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

Java 项目构建与依赖管理(Maven / Gradle)
Java 项目构建与依赖管理(Maven / Gradle)

本专题系统讲解 Java 项目构建与依赖管理的完整体系,重点覆盖 Maven 与 Gradle 的核心概念、项目生命周期、依赖冲突解决、多模块项目管理、构建加速与版本发布规范。通过真实项目结构示例,帮助学习者掌握 从零搭建、维护到发布 Java 工程的标准化流程,提升在实际团队开发中的工程能力与协作效率。

10

2026.01.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.4万人学习

C# 教程
C# 教程

共94课时 | 6.5万人学习

Java 教程
Java 教程

共578课时 | 45.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号