1. Java面向对象编程三大特性深度解析作为一名有十年Java开发经验的老手我经常被问到关于面向对象编程OOP的核心概念问题。今天我就来聊聊Java中多态、封装和继承这三大特性以及构造器的关键作用。这些不仅是面试高频考点更是日常开发中必须掌握的编程基本功。在实际项目中我发现很多开发者对这些概念的理解停留在表面导致代码质量不高。比如滥用继承导致类层次混乱错误使用多态引发运行时异常或者封装不彻底造成数据安全问题。通过本文我将结合真实案例和代码示例带你深入理解这些概念的本质和应用技巧。2. 封装安全第一的编程哲学2.1 封装的核心思想封装Encapsulation是OOP的第一道防线。它的本质是将数据和行为捆绑在一起并对对象内部细节进行隐藏。就像我们使用手机不需要了解内部电路一样好的封装让使用者只需关注做什么而非怎么做。在Java中封装主要通过访问修饰符实现private仅本类可见protected本包及子类可见public完全公开默认无修饰符本包可见重要原则成员变量应该private化通过public方法提供访问控制。这就是著名的数据隐藏原则。2.2 封装的实战应用来看一个银行账户的封装示例public class BankAccount { private String accountNumber; private double balance; public BankAccount(String accountNumber) { this.accountNumber accountNumber; this.balance 0.0; } public void deposit(double amount) { if (amount 0) { balance amount; } else { throw new IllegalArgumentException(存款金额必须大于0); } } public void withdraw(double amount) { if (amount 0 amount balance) { balance - amount; } else { throw new IllegalArgumentException(取款金额无效); } } public double getBalance() { return balance; } }这个例子展示了几个关键点账户号和余额设为private防止外部直接修改通过public方法控制存款/取款操作在方法中添加业务规则校验2.3 封装的最佳实践最小化访问权限能用private就不用default能用default就不用protected不变性设计对于不应被修改的字段使用final修饰防御性拷贝返回可变对象时返回其拷贝而非引用参数校验所有public方法都应验证输入参数常见错误过度暴露实现细节如返回内部数组引用忽略参数校验导致数据不一致滥用protected破坏封装性3. 继承代码复用的双刃剑3.1 继承的基本概念继承Inheritance允许我们基于已有类创建新类实现代码复用。Java中使用extends关键字实现单继承接口可以实现多继承。继承的典型场景IS-A关系如Dog is an Animal需要扩展或修改父类功能多态应用的基础3.2 继承的深度解析看一个图形类的继承示例class Shape { private String color; public Shape(String color) { this.color color; } public double area() { return 0; // 默认实现 } public String getColor() { return color; } } class Circle extends Shape { private double radius; public Circle(String color, double radius) { super(color); this.radius radius; } Override public double area() { return Math.PI * radius * radius; } }继承的关键点子类通过super调用父类构造器可以重写(override)父类方法子类可以添加新属性和方法3.3 继承的使用原则里氏替换原则(LSP)子类必须能够替换父类而不影响程序正确性组合优于继承优先考虑组合而非继承除非确实是IS-A关系避免深度继承继承层次不宜过深通常不超过3层禁止继承的工具类用final修饰不应被继承的类常见陷阱滥用继承导致类爆炸破坏父类不变性忽略super调用导致初始化问题重写时违反父类约定4. 多态灵活编程的艺术4.1 多态的本质多态Polymorphism指同一操作作用于不同对象可以产生不同行为。Java中主要通过方法重写和接口实现多态。多态的实现方式编译时多态方法重载运行时多态方法重写4.2 多态的典型应用继续使用Shape类的例子public class PolymorphismDemo { public static void main(String[] args) { Shape[] shapes new Shape[3]; shapes[0] new Circle(Red, 5.0); shapes[1] new Rectangle(Blue, 4.0, 6.0); shapes[2] new Triangle(Green, 3.0, 4.0); for (Shape shape : shapes) { System.out.println(shape.getColor() shape area: shape.area()); } } }这个例子展示了多态的强大之处统一处理不同类型的Shape运行时根据实际类型调用正确的area()实现新增Shape子类无需修改遍历代码4.3 多态的高级特性动态绑定方法调用在运行时确定instanceof检查有时需要判断具体类型强制类型转换向下转型的风险与技巧注意滥用instanceof和类型转换通常是设计缺陷的信号应考虑重构。5. 构造器对象诞生的关键5.1 构造器的基础知识构造器Constructor是创建对象时调用的特殊方法。它的核心职责是初始化对象状态。构造器特点与类同名无返回类型连void都没有可以重载默认提供无参构造器除非定义了其他构造器5.2 构造器的进阶用法public class Employee { private String name; private int age; private String department; // 全参数构造器 public Employee(String name, int age, String department) { this.name name; this.age age; this.department department; } // 构造器链 public Employee(String name) { this(name, 30, General); // 调用全参构造器 } // 静态工厂方法 public static Employee createDeveloper(String name, int age) { return new Employee(name, age, Development); } }构造器使用技巧构造器链通过this()调用其他构造器工厂方法提供更有意义的创建方式不可变对象通过构造器完成所有初始化5.3 构造器与继承的关系子类构造器必须直接或间接调用父类构造器显式调用super(...)必须作为第一行隐式调用如果省略super编译器会自动插入super()常见错误忘记调用super导致编译错误在super前执行其他操作循环调用构造器6. 四大特性的协同应用6.1 设计模式中的经典组合模板方法模式完美展示了这些特性的协作abstract class Game { // 封装通用流程 public final void play() { initialize(); startPlay(); endPlay(); } // 继承扩展点 abstract void initialize(); abstract void startPlay(); abstract void endPlay(); } class Cricket extends Game { Override void initialize() { System.out.println(Cricket Game Initialized); } Override void startPlay() { System.out.println(Cricket Game Started); } Override void endPlay() { System.out.println(Cricket Game Finished); } }这个模式中封装了play()算法骨架通过继承提供具体实现多态调用子类方法构造器初始化对象状态6.2 实际项目中的应用建议领域模型设计封装业务规则和数据合理使用继承表达领域关系多态处理不同业务场景框架扩展点定义抽象基类或接口通过继承实现定制逻辑运行时多态调用扩展实现API设计良好的封装保证API稳定性适当使用继承减少重复代码多态提供灵活的使用方式7. 常见面试问题深度剖析7.1 多态的实现原理Java多态通过JVM的方法表Method Table实现。每个类都有一个方法表包含所有可被调用的方法。调用虚方法时JVM会根据对象的实际类查找方法表找到正确的方法实现。7.2 构造器能否被重写构造器不是普通方法不能被重写。因为构造器名必须与类名相同子类构造器与父类构造器名不同构造器没有返回类型不符合重写要求7.3 封装与安全的关系良好的封装是系统安全的基础防止非法数据修改控制访问权限隐藏实现细节减少攻击面便于添加安全检查逻辑7.4 继承的替代方案当继承不适用时可以考虑组合将功能委托给其他对象策略模式通过接口切换算法装饰器模式动态添加功能8. 性能考量与最佳实践8.1 多态的性能影响方法调用类型性能特点静态绑定private/static/final方法最快编译期确定虚方法调用普通实例方法稍慢需要方法表查找接口方法调用最慢需要搜索实现类优化建议对性能关键代码考虑使用final方法避免深度继承层次谨慎使用接口多态8.2 对象创建优化重用对象对于不可变对象可以缓存重用对象池对创建成本高的对象使用对象池延迟初始化仅在需要时创建对象避免在循环中创建对象8.3 内存占用考量每个对象都有对象头开销约12-16字节继承会增加内存占用父类字段内部类会持有外部类引用9. Java 8的新特性影响9.1 默认方法对继承的影响接口现在可以包含方法实现default方法这改变了传统的继承规则interface Flyable { default void fly() { System.out.println(Flying normally); } } class Bird implements Flyable { // 可以选择重写或使用默认实现 }注意事项菱形继承问题类实现两个有相同默认方法的接口使用super.specificMethod()调用特定接口的默认方法9.2 记录类Record的封装Java 14引入的Record类提供了更简洁的不可变数据封装public record Point(int x, int y) { // 编译器自动生成 // final字段、构造器、equals/hashCode/toString }Record的特点隐式final类和字段自动生成的规范方法简洁的语法表达纯数据9.3 密封类Sealed Class对继承的控制Java 17引入密封类可以精确控制哪些类可以继承自己public sealed class Shape permits Circle, Square, Rectangle { // 只有Circle、Square、Rectangle可以继承Shape }这解决了传统继承的两个问题无限制的继承导致类层次失控需要final和non-final的二元选择10. 实战经验与避坑指南10.1 多态与instanceof的微妙关系虽然多态旨在避免类型检查但有时instanceof是必要的if (shape instanceof Circle) { Circle circle (Circle) shape; double radius circle.getRadius(); // 特殊处理圆形 }何时使用instanceof需要访问子类特有方法时实现equals方法时处理遗留代码或第三方库时警告频繁使用instanceof通常是设计问题的信号应考虑重构。10.2 构造器中的异常处理构造器中抛出异常会导致对象创建失败public class ResourceHolder { private final Resource resource; public ResourceHolder(String config) throws ResourceException { this.resource new Resource(config); // 可能抛出异常 } }处理建议在构造器中完成所有有效性检查避免构造器中执行可能失败的操作考虑使用工厂方法封装复杂初始化10.3 继承与组合的选择标准使用继承当确实是IS-A关系需要多态行为父类是抽象或设计用于继承使用组合当只是需要复用代码可能改变实现方式关系是HAS-A而非IS-A10.4 封装与性能的权衡有时为了性能需要打破封装public class Vector3D { public float x, y, z; // 公开字段以提高性能 // 方法省略 }打破封装的原则仅在性能关键路径上类是不可变的或线程安全的有充分的文档说明11. 现代Java开发的最佳实践11.1 不可变对象设计不可变对象的优势线程安全易于缓存和共享避免意外修改实现模式所有字段final不提供setter方法防御性拷贝可变对象11.2 面向接口编程好处降低耦合便于测试和替换实现支持多态示例public interface Repository { void save(Entity entity); Entity findById(String id); } public class JpaRepository implements Repository { // 实现省略 }11.3 谨慎使用继承现代Java更倾向于组合而非继承接口而非抽象类委托而非扩展11.4 防御性编程技巧参数验证不可变集合深拷贝空对象模式12. 工具与调试技巧12.1 诊断多态问题使用调试器查看运行时类型检查方法是否被正确重写使用override注解确保重写正确12.2 分析内存泄漏使用VisualVM或JProfiler检查意外保持的对象引用特别注意静态集合和监听器12.3 性能分析工具JMCJava Mission ControlAsync ProfilerJMHJava Microbenchmark Harness12.4 代码质量检查使用SonarQube静态分析Checkstyle编码规范检查SpotBugs查找潜在错误13. 从语言设计角度看OOP特性13.1 Java与C的对比特性JavaC继承单继承多继承接口支持抽象类虚方法默认虚方法需显式声明内存管理自动GC手动/RAII13.2 动态语言的多态实现JavaScript/Python等动态语言的多态基于鸭子类型运行时方法解析更灵活但更易出错13.3 函数式编程的影响现代Java融合了OOP和FPLambda表达式流式API不可变集合14. 架构层面的应用思考14.1 模块化设计高内聚低耦合接口隔离原则依赖倒置原则14.2 领域驱动设计实体与值对象聚合根封装领域服务多态14.3 微服务架构服务接口封装多态的消息处理器继承与组合在框架中的应用15. 学习路线与资源推荐15.1 经典书籍《Effective Java》- Joshua Bloch《Java编程思想》- Bruce Eckel《设计模式》- GoF15.2 在线资源Oracle官方Java教程Baeldung Java系列Java Code Geeks15.3 实践项目设计一个图形编辑器实现简单的IoC容器构建领域模型框架16. 未来发展趋势16.1 Valhalla项目值类型专用泛型对OOP模型的影响16.2 Loom项目虚拟线程结构化并发对对象生命周期的影响16.3 其他JVM语言的影响Kotlin的类设计Scala的混入特质Groovy的动态特性17. 个人经验分享在我多年的Java开发生涯中有几个关于OOP特性的深刻体会封装是维护性的基石那些最难维护的系统往往都是封装被破坏得最严重的。我曾经接手过一个项目几乎所有字段都是public的结果任何修改都可能引发连锁反应。继承要慎之又慎除非确定是严格的IS-A关系否则优先考虑组合。我见过一个类继承层次达到8层的系统添加新功能就像在走迷宫。多态是一把双刃剑设计良好的多态能让系统灵活扩展但滥用多态特别是配合instanceof会让代码难以理解和维护。构造器要简单可靠构造器中做太多工作尤其是IO操作是常见的错误来源。保持构造器简单使用工厂方法处理复杂初始化。最后一个小技巧在IDE中设置代码模板自动生成带有参数校验的setter方法和构造器可以大大提高编码效率同时保证代码质量。
Java面向对象编程三大特性与构造器深度解析
1. Java面向对象编程三大特性深度解析作为一名有十年Java开发经验的老手我经常被问到关于面向对象编程OOP的核心概念问题。今天我就来聊聊Java中多态、封装和继承这三大特性以及构造器的关键作用。这些不仅是面试高频考点更是日常开发中必须掌握的编程基本功。在实际项目中我发现很多开发者对这些概念的理解停留在表面导致代码质量不高。比如滥用继承导致类层次混乱错误使用多态引发运行时异常或者封装不彻底造成数据安全问题。通过本文我将结合真实案例和代码示例带你深入理解这些概念的本质和应用技巧。2. 封装安全第一的编程哲学2.1 封装的核心思想封装Encapsulation是OOP的第一道防线。它的本质是将数据和行为捆绑在一起并对对象内部细节进行隐藏。就像我们使用手机不需要了解内部电路一样好的封装让使用者只需关注做什么而非怎么做。在Java中封装主要通过访问修饰符实现private仅本类可见protected本包及子类可见public完全公开默认无修饰符本包可见重要原则成员变量应该private化通过public方法提供访问控制。这就是著名的数据隐藏原则。2.2 封装的实战应用来看一个银行账户的封装示例public class BankAccount { private String accountNumber; private double balance; public BankAccount(String accountNumber) { this.accountNumber accountNumber; this.balance 0.0; } public void deposit(double amount) { if (amount 0) { balance amount; } else { throw new IllegalArgumentException(存款金额必须大于0); } } public void withdraw(double amount) { if (amount 0 amount balance) { balance - amount; } else { throw new IllegalArgumentException(取款金额无效); } } public double getBalance() { return balance; } }这个例子展示了几个关键点账户号和余额设为private防止外部直接修改通过public方法控制存款/取款操作在方法中添加业务规则校验2.3 封装的最佳实践最小化访问权限能用private就不用default能用default就不用protected不变性设计对于不应被修改的字段使用final修饰防御性拷贝返回可变对象时返回其拷贝而非引用参数校验所有public方法都应验证输入参数常见错误过度暴露实现细节如返回内部数组引用忽略参数校验导致数据不一致滥用protected破坏封装性3. 继承代码复用的双刃剑3.1 继承的基本概念继承Inheritance允许我们基于已有类创建新类实现代码复用。Java中使用extends关键字实现单继承接口可以实现多继承。继承的典型场景IS-A关系如Dog is an Animal需要扩展或修改父类功能多态应用的基础3.2 继承的深度解析看一个图形类的继承示例class Shape { private String color; public Shape(String color) { this.color color; } public double area() { return 0; // 默认实现 } public String getColor() { return color; } } class Circle extends Shape { private double radius; public Circle(String color, double radius) { super(color); this.radius radius; } Override public double area() { return Math.PI * radius * radius; } }继承的关键点子类通过super调用父类构造器可以重写(override)父类方法子类可以添加新属性和方法3.3 继承的使用原则里氏替换原则(LSP)子类必须能够替换父类而不影响程序正确性组合优于继承优先考虑组合而非继承除非确实是IS-A关系避免深度继承继承层次不宜过深通常不超过3层禁止继承的工具类用final修饰不应被继承的类常见陷阱滥用继承导致类爆炸破坏父类不变性忽略super调用导致初始化问题重写时违反父类约定4. 多态灵活编程的艺术4.1 多态的本质多态Polymorphism指同一操作作用于不同对象可以产生不同行为。Java中主要通过方法重写和接口实现多态。多态的实现方式编译时多态方法重载运行时多态方法重写4.2 多态的典型应用继续使用Shape类的例子public class PolymorphismDemo { public static void main(String[] args) { Shape[] shapes new Shape[3]; shapes[0] new Circle(Red, 5.0); shapes[1] new Rectangle(Blue, 4.0, 6.0); shapes[2] new Triangle(Green, 3.0, 4.0); for (Shape shape : shapes) { System.out.println(shape.getColor() shape area: shape.area()); } } }这个例子展示了多态的强大之处统一处理不同类型的Shape运行时根据实际类型调用正确的area()实现新增Shape子类无需修改遍历代码4.3 多态的高级特性动态绑定方法调用在运行时确定instanceof检查有时需要判断具体类型强制类型转换向下转型的风险与技巧注意滥用instanceof和类型转换通常是设计缺陷的信号应考虑重构。5. 构造器对象诞生的关键5.1 构造器的基础知识构造器Constructor是创建对象时调用的特殊方法。它的核心职责是初始化对象状态。构造器特点与类同名无返回类型连void都没有可以重载默认提供无参构造器除非定义了其他构造器5.2 构造器的进阶用法public class Employee { private String name; private int age; private String department; // 全参数构造器 public Employee(String name, int age, String department) { this.name name; this.age age; this.department department; } // 构造器链 public Employee(String name) { this(name, 30, General); // 调用全参构造器 } // 静态工厂方法 public static Employee createDeveloper(String name, int age) { return new Employee(name, age, Development); } }构造器使用技巧构造器链通过this()调用其他构造器工厂方法提供更有意义的创建方式不可变对象通过构造器完成所有初始化5.3 构造器与继承的关系子类构造器必须直接或间接调用父类构造器显式调用super(...)必须作为第一行隐式调用如果省略super编译器会自动插入super()常见错误忘记调用super导致编译错误在super前执行其他操作循环调用构造器6. 四大特性的协同应用6.1 设计模式中的经典组合模板方法模式完美展示了这些特性的协作abstract class Game { // 封装通用流程 public final void play() { initialize(); startPlay(); endPlay(); } // 继承扩展点 abstract void initialize(); abstract void startPlay(); abstract void endPlay(); } class Cricket extends Game { Override void initialize() { System.out.println(Cricket Game Initialized); } Override void startPlay() { System.out.println(Cricket Game Started); } Override void endPlay() { System.out.println(Cricket Game Finished); } }这个模式中封装了play()算法骨架通过继承提供具体实现多态调用子类方法构造器初始化对象状态6.2 实际项目中的应用建议领域模型设计封装业务规则和数据合理使用继承表达领域关系多态处理不同业务场景框架扩展点定义抽象基类或接口通过继承实现定制逻辑运行时多态调用扩展实现API设计良好的封装保证API稳定性适当使用继承减少重复代码多态提供灵活的使用方式7. 常见面试问题深度剖析7.1 多态的实现原理Java多态通过JVM的方法表Method Table实现。每个类都有一个方法表包含所有可被调用的方法。调用虚方法时JVM会根据对象的实际类查找方法表找到正确的方法实现。7.2 构造器能否被重写构造器不是普通方法不能被重写。因为构造器名必须与类名相同子类构造器与父类构造器名不同构造器没有返回类型不符合重写要求7.3 封装与安全的关系良好的封装是系统安全的基础防止非法数据修改控制访问权限隐藏实现细节减少攻击面便于添加安全检查逻辑7.4 继承的替代方案当继承不适用时可以考虑组合将功能委托给其他对象策略模式通过接口切换算法装饰器模式动态添加功能8. 性能考量与最佳实践8.1 多态的性能影响方法调用类型性能特点静态绑定private/static/final方法最快编译期确定虚方法调用普通实例方法稍慢需要方法表查找接口方法调用最慢需要搜索实现类优化建议对性能关键代码考虑使用final方法避免深度继承层次谨慎使用接口多态8.2 对象创建优化重用对象对于不可变对象可以缓存重用对象池对创建成本高的对象使用对象池延迟初始化仅在需要时创建对象避免在循环中创建对象8.3 内存占用考量每个对象都有对象头开销约12-16字节继承会增加内存占用父类字段内部类会持有外部类引用9. Java 8的新特性影响9.1 默认方法对继承的影响接口现在可以包含方法实现default方法这改变了传统的继承规则interface Flyable { default void fly() { System.out.println(Flying normally); } } class Bird implements Flyable { // 可以选择重写或使用默认实现 }注意事项菱形继承问题类实现两个有相同默认方法的接口使用super.specificMethod()调用特定接口的默认方法9.2 记录类Record的封装Java 14引入的Record类提供了更简洁的不可变数据封装public record Point(int x, int y) { // 编译器自动生成 // final字段、构造器、equals/hashCode/toString }Record的特点隐式final类和字段自动生成的规范方法简洁的语法表达纯数据9.3 密封类Sealed Class对继承的控制Java 17引入密封类可以精确控制哪些类可以继承自己public sealed class Shape permits Circle, Square, Rectangle { // 只有Circle、Square、Rectangle可以继承Shape }这解决了传统继承的两个问题无限制的继承导致类层次失控需要final和non-final的二元选择10. 实战经验与避坑指南10.1 多态与instanceof的微妙关系虽然多态旨在避免类型检查但有时instanceof是必要的if (shape instanceof Circle) { Circle circle (Circle) shape; double radius circle.getRadius(); // 特殊处理圆形 }何时使用instanceof需要访问子类特有方法时实现equals方法时处理遗留代码或第三方库时警告频繁使用instanceof通常是设计问题的信号应考虑重构。10.2 构造器中的异常处理构造器中抛出异常会导致对象创建失败public class ResourceHolder { private final Resource resource; public ResourceHolder(String config) throws ResourceException { this.resource new Resource(config); // 可能抛出异常 } }处理建议在构造器中完成所有有效性检查避免构造器中执行可能失败的操作考虑使用工厂方法封装复杂初始化10.3 继承与组合的选择标准使用继承当确实是IS-A关系需要多态行为父类是抽象或设计用于继承使用组合当只是需要复用代码可能改变实现方式关系是HAS-A而非IS-A10.4 封装与性能的权衡有时为了性能需要打破封装public class Vector3D { public float x, y, z; // 公开字段以提高性能 // 方法省略 }打破封装的原则仅在性能关键路径上类是不可变的或线程安全的有充分的文档说明11. 现代Java开发的最佳实践11.1 不可变对象设计不可变对象的优势线程安全易于缓存和共享避免意外修改实现模式所有字段final不提供setter方法防御性拷贝可变对象11.2 面向接口编程好处降低耦合便于测试和替换实现支持多态示例public interface Repository { void save(Entity entity); Entity findById(String id); } public class JpaRepository implements Repository { // 实现省略 }11.3 谨慎使用继承现代Java更倾向于组合而非继承接口而非抽象类委托而非扩展11.4 防御性编程技巧参数验证不可变集合深拷贝空对象模式12. 工具与调试技巧12.1 诊断多态问题使用调试器查看运行时类型检查方法是否被正确重写使用override注解确保重写正确12.2 分析内存泄漏使用VisualVM或JProfiler检查意外保持的对象引用特别注意静态集合和监听器12.3 性能分析工具JMCJava Mission ControlAsync ProfilerJMHJava Microbenchmark Harness12.4 代码质量检查使用SonarQube静态分析Checkstyle编码规范检查SpotBugs查找潜在错误13. 从语言设计角度看OOP特性13.1 Java与C的对比特性JavaC继承单继承多继承接口支持抽象类虚方法默认虚方法需显式声明内存管理自动GC手动/RAII13.2 动态语言的多态实现JavaScript/Python等动态语言的多态基于鸭子类型运行时方法解析更灵活但更易出错13.3 函数式编程的影响现代Java融合了OOP和FPLambda表达式流式API不可变集合14. 架构层面的应用思考14.1 模块化设计高内聚低耦合接口隔离原则依赖倒置原则14.2 领域驱动设计实体与值对象聚合根封装领域服务多态14.3 微服务架构服务接口封装多态的消息处理器继承与组合在框架中的应用15. 学习路线与资源推荐15.1 经典书籍《Effective Java》- Joshua Bloch《Java编程思想》- Bruce Eckel《设计模式》- GoF15.2 在线资源Oracle官方Java教程Baeldung Java系列Java Code Geeks15.3 实践项目设计一个图形编辑器实现简单的IoC容器构建领域模型框架16. 未来发展趋势16.1 Valhalla项目值类型专用泛型对OOP模型的影响16.2 Loom项目虚拟线程结构化并发对对象生命周期的影响16.3 其他JVM语言的影响Kotlin的类设计Scala的混入特质Groovy的动态特性17. 个人经验分享在我多年的Java开发生涯中有几个关于OOP特性的深刻体会封装是维护性的基石那些最难维护的系统往往都是封装被破坏得最严重的。我曾经接手过一个项目几乎所有字段都是public的结果任何修改都可能引发连锁反应。继承要慎之又慎除非确定是严格的IS-A关系否则优先考虑组合。我见过一个类继承层次达到8层的系统添加新功能就像在走迷宫。多态是一把双刃剑设计良好的多态能让系统灵活扩展但滥用多态特别是配合instanceof会让代码难以理解和维护。构造器要简单可靠构造器中做太多工作尤其是IO操作是常见的错误来源。保持构造器简单使用工厂方法处理复杂初始化。最后一个小技巧在IDE中设置代码模板自动生成带有参数校验的setter方法和构造器可以大大提高编码效率同时保证代码质量。