OOP 四大支柱:封装、继承、多态、抽象,用停车场收费系统一次性讲透
OOP 的4 大核心概念也被称为“四大支柱”是封装Encapsulation、继承Inheritance、多态Polymorphism和抽象Abstraction。这 4 个概念不是孤立的而是层层递进的。如果说 Java 代码是一座大厦封装就是砌墙的砖块保护数据继承就是楼层的骨架复用代码多态就是通用的接口插座统一接口而抽象就是建筑设计图隐藏复杂细节。面向对象编程不是语法而是一种世界观。理解这 4 个概念你就能看懂 90% 的设计模式。当我们说 Java 是“面向对象”的语言时到底在说什么不是因为它有class关键字而是因为它完整地实现了 OOP 的四大支柱封装Encapsulation、继承Inheritance、多态Polymorphism和抽象Abstraction。很多程序员工作两三年能熟练使用private、extends、Override但被问到“它们分别解决了什么问题”时却支支吾吾。今天我们用停车场收费系统作为贯穿案例从**“为什么要这么设计”**的角度把这 4 个概念彻底刻进脑子里。一、封装Encapsulation把数据锁进保险柜1. 定义将属性状态私有化通过公共方法行为来访问和修改。核心思想是“告诉不要询问Tell, Don‘t Ask”。2. 停车场案例错误示范 vs 正确示范❌ 错误未封装车开进来外面的系统直接修改车辆离开时间。classCar{StringplateNumber;longenterTime;longexitTime;// 公开可改极易出错}// 外部代码可以随意乱改CarcarnewCar();car.exitTimeSystem.currentTimeMillis()-10000;// 未进场就离场数据错乱✅ 正确封装把属性藏起来只允许通过停车场的收费逻辑来结算。publicclassCar{privateStringplateNumber;// private 隐藏privatelongenterTime;privateLongexitTime;// 未离场为 nullpublicCar(StringplateNumber){this.plateNumberplateNumber;this.enterTimeSystem.currentTimeMillis();}// 只提供必要的公共方法publicvoidcheckout(){this.exitTimeSystem.currentTimeMillis();}publiclonggetParkingDuration(){if(exitTimenull){thrownewIllegalStateException(车辆尚未离场);}returnexitTime-enterTime;// 计算逻辑封装在内}publicStringgetPlateNumber(){// 只读访问returnplateNumber;}}3. 封装解决了什么问题安全性防止外部代码破坏对象的内部状态。维护性修改计算逻辑如改为按分钟计费只需要改类内部外部调用方完全不受影响。控制权类可以校验输入比如车牌号不为空。一句话记住封装private字段 public方法 封装。二、继承Inheritance站在巨人的肩膀上1. 定义子类Subclass继承父类Superclass的属性和方法实现IS-A是一种关系。核心目的是代码复用和建立层次结构。2. 停车场案例构建车辆体系停车场里不光有小轿车Car还有摩托车Motorcycle和卡车Truck。它们都有车牌号plateNumber和入场时间enterTime但收费规则不同。✅ 正确继承// 1. 父类基类publicabstractclassVehicle{privateStringplateNumber;privatelongenterTime;publicVehicle(StringplateNumber){this.plateNumberplateNumber;this.enterTimeSystem.currentTimeMillis();}publicStringgetPlateNumber(){returnplateNumber;}publiclonggetEnterTime(){returnenterTime;}// 抽象方法强制子类实现自己的计费逻辑publicabstractdoublecalculateFee(longexitTime);}// 2. 子类派生类——小轿车publicclassCarextendsVehicle{privatestaticfinaldoubleRATE5.0;// 5元/小时publicCar(StringplateNumber){super(plateNumber);}OverridepublicdoublecalculateFee(longexitTime){longhours(exitTime-getEnterTime())/(1000*60*60);returnhours*RATE;}}// 3. 子类——摩托车半价publicclassMotorcycleextendsVehicle{privatestaticfinaldoubleRATE2.5;publicMotorcycle(StringplateNumber){super(plateNumber);}OverridepublicdoublecalculateFee(longexitTime){longhours(exitTime-getEnterTime())/(1000*60*60);returnhours*RATE;}}3. Java 继承的重要规则单继承一个类只能继承一个父类解决了 C 多继承的菱形继承问题。传递性子类自动拥有父类定义的公共public/protected属性和方法。构造方法子类构造方法必须通过super()调用父类构造方法。一句话记住继承子类 extends 父类复用代码扩展差异。三、多态Polymorphism同一个接口不同的表现1. 定义同一个行为方法调用在不同的对象上产生不同的执行结果。多态分为编译时多态重载 Overload和运行时多态重写 Override。我们重点讲运行时多态——这是 OOP 的灵魂。2. 停车场案例统一管理分别结算有了继承和多态停车场的收银台系统可以写出极简且通用的代码// 停车场收银台publicclassParkingLot{// 多态的核心父类引用指向子类对象publicvoidcheckoutVehicle(Vehiclevehicle){longexitTimeSystem.currentTimeMillis();doublefeevehicle.calculateFee(exitTime);// 这里调用的是子类重写的方法System.out.println(车牌vehicle.getPlateNumber()费用fee 元);}publicstaticvoidmain(String[]args){ParkingLotlotnewParkingLot();// 同一段代码传入不同子类结果完全不同VehiclecarnewCar(京A12345);VehiclebikenewMotorcycle(京B67890);lot.checkoutVehicle(car);// 输出 5.0 元/小时计费lot.checkoutVehicle(bike);// 输出 2.5 元/小时计费}}3. 多态的 3 个必要条件面试必答继承或接口实现。重写子类覆盖父类的方法。父类引用指向子类对象Vehicle v new Car();。4. 重载Overloadvs 重写Override这是面试中的高频混淆点对比维度重载Overload重写Override发生位置同一个类中子类和父类之间方法名必须相同必须相同参数列表必须不同个数/类型/顺序必须相同返回类型可以不同必须相同或其子类——协变返回访问修饰符随意子类权限不能更严格如父类 public子类不能 private绑定时机编译时静态绑定运行时动态绑定一句话记住多态编译看左边运行看右边。四、抽象Abstraction只定义规矩不做事1. 定义隐藏具体的实现细节仅向外界暴露必要的行为契约。在 Java 中通过抽象类Abstract Class和接口Interface实现。2. 抽象 vs 封装的区别最容易混淆封装隐藏数据不让看内部属性。抽象隐藏实现不让看内部算法只告诉你“我能做什么”。3. 停车场案例用接口升级架构如果停车场不仅收汽车、摩托车还要收自行车Bicycle但自行车不需要“离场时间”这种复杂逻辑。此时用抽象类可能太沉重可以用接口定义更轻量的契约// 定义收费能力接口publicinterfaceChargeable{doublecalculateFee(longexitTime);StringgetPlateNumber();}// 自行车实现接口publicclassBicycleimplementsChargeable{privatestaticfinaldoubleFIXED_FEE1.0;privateStringplateNumber;publicBicycle(StringplateNumber){this.plateNumberplateNumber;}OverridepublicdoublecalculateFee(longexitTime){returnFIXED_FEE;// 无论停多久都收 1 元}OverridepublicStringgetPlateNumber(){returnplateNumber;}}// 收银台只需面向接口编程publicvoidcheckout(Chargeablechargeable){doublefeechargeable.calculateFee(System.currentTimeMillis());System.out.println(费用fee);}4. 抽象类 vs 接口Java 8 后怎么选对比维度抽象类Abstract Class接口Interface关键字extendsimplements成员变量可以有实例变量只能是public static final常量构造方法有无方法实现可以有具体方法Java 8 后可用default/static方法Java 9 后有private方法状态存储可以存储状态不能存储状态多继承不支持单继承支持多实现使用场景存在 IS-A 关系且需要共享代码存在 CAN-DO 关系定义行为契约五、四大支柱的“协作关系”一张图看懂┌─────────────────────────────────────────────────────────────┐ │ 抽象Abstraction │ │ 定义“做什么”接口/抽象类契约 │ └─────────────────────────────────────────────────────────────┘ │ ┌────────────────────┼────────────────────┐ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ 封装 │ │ 继承 │ │ 多态 │ │ 保护数据安全 │ │ 复用父类代码 │ │ 统一接口调用 │ └──────────────┘ └──────────────┘ └──────────────┘ 协作逻辑 1. 抽象抽象类/接口规定了“车辆必须能计费”。 2. 继承Car extends Vehicle让子类获得了父类的基础属性和通用逻辑。 3. 封装private enterTime保护了时间数据不被随意篡改。 4. 多态Vehicle v new Car()让收银台能用统一方法处理所有车辆。六、实战避坑总结概念核心关键词常见误用封装private、getter/setter用getter/setter把所有字段暴露破坏封装盲目生成 Setter 让对象变可变继承extends、super、IS-A为了复用代码滥用继承比如Stack extends Vector违反里氏替换原则LSP优先考虑组合Composition多态Override、父类引用子类对象忘记在子类加Override注解虽然语法没问题但容易造成“重载”而非“重写”的误判混淆Overload和Override抽象abstract、interface盲目用抽象类其实应该用接口Java 8 后依然拒绝使用接口的default方法进行接口演进七、思考题检验是否真的懂了// 问题 1下面的代码体现了 OOP 的哪个概念publicclassDatabase{privateStringurl;privateStringusername;privateStringpassword;publicvoidconnect(){// 复杂连接逻辑}}// 问题 2下面的代码中有多少处体现了多态分别是什么ListStringlistnewArrayList();list.add(Hello);// 问题 3一个文件里同时定义了 interface Animal 和 class Dog implements Animal这主要体现了 OOP 的哪两个支柱答案选中下方空白区域查看封装。url、username、password都是private只能通过connect()方法间接操作。有 1 处List是接口ArrayList是实现类ListString list new ArrayList();体现了面向接口编程的多态。体现了抽象interface Animal定义行为契约和多态Dog可以当作Animal类型使用。总结终极记忆口诀封装锁住数据不让乱改。继承复用代码避免重复。多态统一接口不同实现。抽象隐藏细节只管能力。掌握这四大支柱你就掌握了面向对象编程的“道”。剩下的设计模式、框架原理都是在这 4 个基础之上搭建的“术”。如果觉得有收获别忘了点赞、收藏、转发让更多 Javaer 彻底搞懂 OOP 四大支柱我们下篇见发布日期2026-08-24

相关新闻

最新新闻

日新闻

周新闻

月新闻