个人主页北极的代码欢迎来访作者简介java后端学习者❄️个人专栏苍穹外卖日记SSM框架深入JavaWeb✨命运的结局尽可永在不屈的挑战却不可须臾或缺前言大家好我是代码不加冰今天我们来学习java面试必备八股文java基础这一模块感觉看的太多记不住还是一部分一部分的看吧不能急于求成今天主要的内容就是面向对象相关的里面具体的继承多态抽象类方法等等。摘要本文系统讲解了Java面向对象编程的核心概念重点剖析了多态、抽象类和接口三大特性。多态通过继承、重写和父类引用指向子类对象实现一个接口多种实现提升代码复用性和扩展性抽象类作为半成品模板通过抽象方法强制子类实现特定行为接口则定义行为规范支持多实现。文章详细对比了重载与重写的区别澄清了抽象类与接口的关键差异并解释了接口不能包含构造函数的原因。这些面向对象特性共同构成了Java灵活、可扩展的编程范式遵循开闭原则实现代码的高效组织与管理。面向对象是什么面向对象是⼀种编程范式它将现实世界中的事物抽象为对象对象具有属性称为字段或属性和⾏为称为方 法。⾯向对象编程的设计思想是以对象为中⼼通过对象之间的交互来完成程序的功能具有灵活性和可扩展 性通过封装和继承可以更好地应对需求变化。Java⾯向对象的三⼤特性包括封装、继承、多态封装封装是指将对象的属性数据和⾏为⽅法结合在⼀起对外隐藏对象的内部细节仅通过对象 提供的接⼜与外界交互。封装的⽬的是增强安全性和简化编程使得对象更加独⽴。继承继承是⼀种可以使得⼦类⾃动共享⽗类数据结构和⽅法的机制。它是代码复⽤的重要⼿段通过继承 可以建⽴类与类之间的层次关系使得结构更加清晰。多态多态是指允许不同类的对象对同⼀消息作出响应。即同⼀个接口使⽤不同的实例⽽执⾏不同操作。 多态性可以分为编译时多态重载和运⾏时多态重写。它使得程序具有良好的灵活性和扩展性在面向对象编程OOP中多态Polymorphism是指同一个行为方法具有多个不同表现形式或状态的能力。简单来说就是“一个接口多种实现”。同样的操作比如调用speak()方法作用于不同的对象猫、狗、猪会产生不同的结果喵、汪、哼。多态的三个核心条件多态要想成立通常需要满足以下三个条件继承存在父类和子类或者接口与实现类。重写子类重写override了父类的方法。父类引用指向子类对象用父类类型的变量去引用子类创建的对象。生活例子想象一个“开”的动作开汽车- 转动方向盘、踩油门。开飞机- 拉操作杆。开船- 转动舵轮。“开”这个命令是相同的但具体怎么执行取决于你开的交通工具是什么。多态体现在哪几个方面1. 方法重写Override—— 运行时多态这是最重要、最经典的多态体现。指子类重新定义父类中已有的方法。现象同一个方法名在父类和不同子类中有完全不同的实现逻辑。时机程序运行时JVMJava虚拟机会根据实际创建的对象类型而不是变量声明的类型来决定调用哪个方法。例子Animal a new Cat();调用a.speak();实际输出“喵”而不是“动物叫”。代码写的是父类方法但运行时执行的是子类方法。2. 方法重载Overload—— 编译时多态指在同一个类中定义多个同名方法但它们的参数列表个数、类型、顺序不同。现象同一个方法名根据传入参数的不同执行不同的逻辑。时机程序编译时编译器根据参数的类型和数量就决定好要调用哪个具体方法。例子System.out.println()可以打印整数、字符串、小数……这就是重载同一个println名称对应多个不同实现。3. 泛型编程 —— 参数化类型通过类型参数如 Java 的T让代码可以适用于多种数据类型而不需要为每种类型重复写逻辑。现象同一份代码逻辑可以处理Integer、String、Cat等不同类型的对象。例子ListString和ListInteger共用同一套add()、get()方法的代码但操作的元素类型可以不同。这也是一种“多态”思想。补充从不同角度的体现角度体现说明继承体系父类引用指向子类对象父类类型的变量可以引用任何子类对象并调用子类重写的方法接口实现接口引用指向实现类对象不同类实现同一接口后都可以被当作该接口类型使用各自实现自己的逻辑参数传递方法参数为父类或接口类型一个方法可以接收大量不同子类/实现类的对象提高方法的通用性和扩展性一句话总结重写—— 纵向多态父子之间同一个行为不同表现。重载—— 横向多态同一类中同一个名字不同参数。泛型—— 横向多态同一份代码逻辑适用于多种数据类型。多态解决了什么1. 解决“代码复用性差” →提高扩展性痛点如果没有多态每增加一种新类型比如新增Bird类就需要修改核心处理方法。代码会充满if...else if...来判断具体类型既臃肿又容易出错。解决利用多态新增子类只需继承父类或实现接口原有的核心处理代码完全不用修改。例子宠物医院定义“治疗(Animal a)”方法。以后新增Bird、Fish类只要它们是Animal的子类原有治疗代码无需改动直接就能传进来处理。2. 解决代码耦合度高→实现解耦痛点如果代码直接依赖具体类如Dog dog new Dog()那么代码就和“狗”这个具体类绑死了。将来需求变了替换或升级具体类会非常困难。解决多态提倡“面向接口/父类编程”。代码依赖稳定的抽象Animal而不是易变的具体实现Cat、Dog。例子电脑的 USB 接口。电脑只依赖“USB 协议”抽象你插鼠标、键盘、U盘具体实现它都能工作。如果电脑直接依赖“鼠标”那键盘就插不上了。3. 解决代码冗余→简化代码逻辑痛点处理一组不同类型但行为相似的对象时没有多态就得为每种类型单独写一个方法比如feedCat(Cat c)、feedDog(Dog d)代码大量重复。解决只需要写一个参数为父类类型的方法如feed(Animal a)就能接收所有子类对象大大减少重复代码。例子农场喂食。如果不使用多态喂 10 种动物需要写 10 个喂食方法。使用多态写 1 个feed(Animal animal)方法就够了。一句话总结多态的价值多态让写出来的代码可以面向“不变的抽象父类/接口”编程而具体执行时动态地绑定到“变化的实现子类”。这使得代码对扩展开放对修改关闭——即著名的“开闭原则”OCP, Open-Closed Principle。重载与重写的区别重载Overloading和重写Overriding是面向对象中两个容易混淆的概念。它们的核心区别在于重载是同一个类中“方法名相同参数不同”重写是子类对父类方法“重新实现”。下面从几个关键维度对比比较维度重载 (Overloading)重写 (Overriding)发生范围同一个类中子类和父类之间或实现类与接口之间方法名必须相同必须相同参数列表必须不同个数、类型、顺序必须相同包括类型、个数、顺序返回类型可以不同无限制必须相同或是其子类型协变返回访问修饰符可以不同无限制不能比父类更严格如父类是protected子类不能是private异常声明可以不同无限制不能抛出比父类更宽泛的异常可以是更少或更具体的异常绑定时机编译时多态编译器决定调用哪个运行时多态JVM 运行时动态决定目的为同一功能提供多种输入方式如多个构造器、println多种参数修改或扩展父类的行常见错误理解澄清同一个类中能重写吗不能。重写必须发生在继承关系中。同一个类里写相同签名的方法编译会直接报错重复方法。参数相同但返回类型不同是重载吗不是。Java 中仅返回类型不同而参数相同是编译错误不允许。重载的核心是参数列表必须不同。静态方法能被重写吗不能。静态方法是类级别的可以被隐藏Hide但不是重写。子类定义同名静态方法调用时取决于引用类型而非运行时对象。重载同类、同名、不同参编译时决定重写父子、同名、同参、改实现运行时决定什么是抽象类不能实例化不能new你无法直接创建抽象类的对象。比如你定义了abstract class Animal你不能写new Animal()因为“动物”这个概念太抽象没有具体形态。可能有抽象方法抽象方法只有声明没有方法体比如abstract void speak();。这些“未完成”的工作必须由子类去实现重写。所以必须有一个具体的子类去继承这个抽象类完成抽象方法然后才能创建子类的对象来使用。抽象类是一种半成品的类用来作为其他类的模板或基类。它可能有一部分方法已经实现好了共用的还有一部分方法只定义了“签名”但没有写具体实现代码抽象方法需要子类去补全。特点用abstract关键字修饰不能直接创建对象因为它不完整缺少一些方法的实现通常用于表达“一类事物”的上层概念如“动物”、“图形”而不具体指代某个实物例子java abstract class Animal { // 抽象类 String name; void eat() { // 普通方法有实现 System.out.println(吃东西); } abstract void speak(); // 抽象方法没有方法体必须由子类实现 }抽象类 vs 普通类对比维度抽象类普通类能否实例化new❌ 不能✅ 能能否包含抽象方法✅ 能可以有0~多个❌ 不能所有方法必须有实现能否包含普通方法✅ 能✅ 能能否有构造方法✅ 能供子类调用✅ 能能否有成员变量✅ 能✅ 能子类必须做的事必须实现所有抽象方法除非子类也是抽象类可选普通方法可重写也可不重写关键字abstract classclass设计目的作为基类定义通用模板强制子类实现某些行为直接描述具体对象拿来即用关键澄清抽象类可以没有抽象方法吗可以。一个抽象类也可以所有方法都有实现即没有抽象方法。但是即使它没有抽象方法只要被abstract修饰仍然不能new对象。比如java abstract class Base { // 有abstract但无抽象方法 void doSomething() { System.out.println(做某事); } } // 仍然不能 new Base();这种情况下抽象类主要是为了禁止直接实例化强制使用者必须通过子类使用。抽象类的作用提供公共代码复用将多个子类共用的属性、方法写在抽象类中避免重复。强制子类实现特定行为通过抽象方法确保每个子类都有自己版本的实现比如每个动物必须有speak()方法。限制实例化有些类在业务上就不应该有“实例”比如“动物”是一个概念不是具体一只猫或狗用抽象类表达更准确。抽象类和接口对比维度抽象类 (Abstract Class)接口 (Interface)关键字abstract classinterface继承/实现子类使用extends继承实现类使用implements实现多继承/多实现❌ 不支持多继承一个类只能继承一个抽象类✅ 支持多实现一个类可以实现多个接口构造方法✅ 可以有供子类调用❌ 不能有成员变量✅ 可以有各种类型的成员变量实例变量、静态变量默认public static final即常量必须显式初始化普通方法✅ 可以有具体实现的方法Java 8 之前❌ 不能有Java 8✅ 可以用default或static写有方法体的方法访问修饰符方法可以是public、protected、private默认且强制为publicJava 9 允许private方法设计意图代码复用模板模式用于定义一类事物的共同特征行为规范解耦用于定义一类事物能做什么接口的设计初衷是定义行为契约能做什么而不是描述对象的状态有什么属性。所以接口中不能有实例成员变量非static的成员变量。抽象类构造器的定义定义方式与普通类完全相同。java public abstract class Animal { private String name; private int age; // 抽象类的构造器 public Animal(String name, int age) this.name name; // 把参数 name 的值赋给成员变量 name this.age age; // 把参数 age 的值赋给成员变量 age System.out.println(Animal 构造器被调用); } public abstract void speak(); }核心区别谁来调用它这是与普通类最本质的区别。普通类构造器直接通过new关键字调用用来创建自己的实例。Person p new Person(张三, 20); // 调用 Person 的构造器抽象类不能通过new调用。它的构造器是在子类创建对象时由子类构造器通过super()隐式或显式地调用。public class Dog extends Animal { private String breed; public Dog(String name, int age, String breed) { super(name, age); // 显式调用父类抽象类的构造器 this.breed breed; } Override public void speak() { System.out.println(汪汪); } } // 使用 public class Main { public static void main(String[] args) { // Animal a new Animal(无名, 0); // ❌ 编译错误抽象类不能被实例化 Dog dog new Dog(旺财, 3, 金毛); // ✅ 会先调用 Animal 的构造器再调用 Dog 的构造器 } } }运行层面创建对象 赋初值从JVMJava虚拟机运行的角度看new Person(张三,20)这一步其实做了两件紧密相连的事在内存中划出一块空间创建出一个空的对象所有成员变量都是默认值比如namenullage0。调用构造方法把你写的赋值代码this.name name执行一遍把具体的值填进去。所以构造方法更像是在“创建好的空对象基础上把具体值填进去”。不过在日常理解中直接认为“构造方法负责创建并初始化对象”完全没问题。补充一个小细节如果没有写构造方法如果一个类你没有写任何构造方法编译器会自动赠送一个无参构造方法比如public Person() {}。这个“看不见”的构造方法什么都不做所以成员变量还是保持JVM给的默认初始值数字类型0booleanfalse引用类型如Stringnull构造器构造方法就是用来给成员变量赋初始值的特殊方法它在new对象时被自动调用保证对象一创建出来就处于一个合理的初始状态。接口可以包含构造函数吗核心原因构造函数用于“创建对象”而接口不能被实例化构造函数的唯一目的在new创建对象时被调用用来初始化对象的成员变量、完成对象创建前的准备工作。接口的特性接口不能被new实例化。你永远写不出new 某个接口()这样的代码。既然接口永远不会有“被创建对象”的那一刻那它的构造函数就永远没有机会被调用。一个永远无法被调用的方法在语法设计上就是无意义的所以 Java 直接禁止接口中包含构造函数。对比抽象类可以有构造函数虽然它也不能被new你可能会有疑问抽象类也不能被new为什么它能有构造函数抽象类接口能否被new实例化❌ 不能❌ 不能能否有构造函数✅ 能❌ 不能构造函数谁调用子类构造器通过super()调用——没有子类调用因为接口没有构造器链的概念关键差异抽象类的构造函数是给子类用的。子类对象被创建时会先调用父类抽象类的构造函数完成从父类继承来的那部分成员变量的初始化。而接口没有成员变量只能有public static final常量也没有“继承父类数据”的概念所以根本不需要、也没有地方可以安放一个构造函数。补充使用抽象类定义一个抽象类实现该接口在抽象类的构造函数中做初始化。然后具体类继承这个抽象类。可以实现接口层面的初始化。接口中的default方法Java 8 之后你可以在接口中定义一个default初始化方法比如default void init()然后要求实现类在适当的时候调用它。但这种方式是“主动调用”不是构造函数那种“自动调用”结语如果对你有帮助请点赞关注收藏你的支持就是我最大的鼓励
【面试必备】Java面向对象三分钟速通:封装、继承、多态,这一篇就够了
发布时间:2026/5/24 20:32:06
个人主页北极的代码欢迎来访作者简介java后端学习者❄️个人专栏苍穹外卖日记SSM框架深入JavaWeb✨命运的结局尽可永在不屈的挑战却不可须臾或缺前言大家好我是代码不加冰今天我们来学习java面试必备八股文java基础这一模块感觉看的太多记不住还是一部分一部分的看吧不能急于求成今天主要的内容就是面向对象相关的里面具体的继承多态抽象类方法等等。摘要本文系统讲解了Java面向对象编程的核心概念重点剖析了多态、抽象类和接口三大特性。多态通过继承、重写和父类引用指向子类对象实现一个接口多种实现提升代码复用性和扩展性抽象类作为半成品模板通过抽象方法强制子类实现特定行为接口则定义行为规范支持多实现。文章详细对比了重载与重写的区别澄清了抽象类与接口的关键差异并解释了接口不能包含构造函数的原因。这些面向对象特性共同构成了Java灵活、可扩展的编程范式遵循开闭原则实现代码的高效组织与管理。面向对象是什么面向对象是⼀种编程范式它将现实世界中的事物抽象为对象对象具有属性称为字段或属性和⾏为称为方 法。⾯向对象编程的设计思想是以对象为中⼼通过对象之间的交互来完成程序的功能具有灵活性和可扩展 性通过封装和继承可以更好地应对需求变化。Java⾯向对象的三⼤特性包括封装、继承、多态封装封装是指将对象的属性数据和⾏为⽅法结合在⼀起对外隐藏对象的内部细节仅通过对象 提供的接⼜与外界交互。封装的⽬的是增强安全性和简化编程使得对象更加独⽴。继承继承是⼀种可以使得⼦类⾃动共享⽗类数据结构和⽅法的机制。它是代码复⽤的重要⼿段通过继承 可以建⽴类与类之间的层次关系使得结构更加清晰。多态多态是指允许不同类的对象对同⼀消息作出响应。即同⼀个接口使⽤不同的实例⽽执⾏不同操作。 多态性可以分为编译时多态重载和运⾏时多态重写。它使得程序具有良好的灵活性和扩展性在面向对象编程OOP中多态Polymorphism是指同一个行为方法具有多个不同表现形式或状态的能力。简单来说就是“一个接口多种实现”。同样的操作比如调用speak()方法作用于不同的对象猫、狗、猪会产生不同的结果喵、汪、哼。多态的三个核心条件多态要想成立通常需要满足以下三个条件继承存在父类和子类或者接口与实现类。重写子类重写override了父类的方法。父类引用指向子类对象用父类类型的变量去引用子类创建的对象。生活例子想象一个“开”的动作开汽车- 转动方向盘、踩油门。开飞机- 拉操作杆。开船- 转动舵轮。“开”这个命令是相同的但具体怎么执行取决于你开的交通工具是什么。多态体现在哪几个方面1. 方法重写Override—— 运行时多态这是最重要、最经典的多态体现。指子类重新定义父类中已有的方法。现象同一个方法名在父类和不同子类中有完全不同的实现逻辑。时机程序运行时JVMJava虚拟机会根据实际创建的对象类型而不是变量声明的类型来决定调用哪个方法。例子Animal a new Cat();调用a.speak();实际输出“喵”而不是“动物叫”。代码写的是父类方法但运行时执行的是子类方法。2. 方法重载Overload—— 编译时多态指在同一个类中定义多个同名方法但它们的参数列表个数、类型、顺序不同。现象同一个方法名根据传入参数的不同执行不同的逻辑。时机程序编译时编译器根据参数的类型和数量就决定好要调用哪个具体方法。例子System.out.println()可以打印整数、字符串、小数……这就是重载同一个println名称对应多个不同实现。3. 泛型编程 —— 参数化类型通过类型参数如 Java 的T让代码可以适用于多种数据类型而不需要为每种类型重复写逻辑。现象同一份代码逻辑可以处理Integer、String、Cat等不同类型的对象。例子ListString和ListInteger共用同一套add()、get()方法的代码但操作的元素类型可以不同。这也是一种“多态”思想。补充从不同角度的体现角度体现说明继承体系父类引用指向子类对象父类类型的变量可以引用任何子类对象并调用子类重写的方法接口实现接口引用指向实现类对象不同类实现同一接口后都可以被当作该接口类型使用各自实现自己的逻辑参数传递方法参数为父类或接口类型一个方法可以接收大量不同子类/实现类的对象提高方法的通用性和扩展性一句话总结重写—— 纵向多态父子之间同一个行为不同表现。重载—— 横向多态同一类中同一个名字不同参数。泛型—— 横向多态同一份代码逻辑适用于多种数据类型。多态解决了什么1. 解决“代码复用性差” →提高扩展性痛点如果没有多态每增加一种新类型比如新增Bird类就需要修改核心处理方法。代码会充满if...else if...来判断具体类型既臃肿又容易出错。解决利用多态新增子类只需继承父类或实现接口原有的核心处理代码完全不用修改。例子宠物医院定义“治疗(Animal a)”方法。以后新增Bird、Fish类只要它们是Animal的子类原有治疗代码无需改动直接就能传进来处理。2. 解决代码耦合度高→实现解耦痛点如果代码直接依赖具体类如Dog dog new Dog()那么代码就和“狗”这个具体类绑死了。将来需求变了替换或升级具体类会非常困难。解决多态提倡“面向接口/父类编程”。代码依赖稳定的抽象Animal而不是易变的具体实现Cat、Dog。例子电脑的 USB 接口。电脑只依赖“USB 协议”抽象你插鼠标、键盘、U盘具体实现它都能工作。如果电脑直接依赖“鼠标”那键盘就插不上了。3. 解决代码冗余→简化代码逻辑痛点处理一组不同类型但行为相似的对象时没有多态就得为每种类型单独写一个方法比如feedCat(Cat c)、feedDog(Dog d)代码大量重复。解决只需要写一个参数为父类类型的方法如feed(Animal a)就能接收所有子类对象大大减少重复代码。例子农场喂食。如果不使用多态喂 10 种动物需要写 10 个喂食方法。使用多态写 1 个feed(Animal animal)方法就够了。一句话总结多态的价值多态让写出来的代码可以面向“不变的抽象父类/接口”编程而具体执行时动态地绑定到“变化的实现子类”。这使得代码对扩展开放对修改关闭——即著名的“开闭原则”OCP, Open-Closed Principle。重载与重写的区别重载Overloading和重写Overriding是面向对象中两个容易混淆的概念。它们的核心区别在于重载是同一个类中“方法名相同参数不同”重写是子类对父类方法“重新实现”。下面从几个关键维度对比比较维度重载 (Overloading)重写 (Overriding)发生范围同一个类中子类和父类之间或实现类与接口之间方法名必须相同必须相同参数列表必须不同个数、类型、顺序必须相同包括类型、个数、顺序返回类型可以不同无限制必须相同或是其子类型协变返回访问修饰符可以不同无限制不能比父类更严格如父类是protected子类不能是private异常声明可以不同无限制不能抛出比父类更宽泛的异常可以是更少或更具体的异常绑定时机编译时多态编译器决定调用哪个运行时多态JVM 运行时动态决定目的为同一功能提供多种输入方式如多个构造器、println多种参数修改或扩展父类的行常见错误理解澄清同一个类中能重写吗不能。重写必须发生在继承关系中。同一个类里写相同签名的方法编译会直接报错重复方法。参数相同但返回类型不同是重载吗不是。Java 中仅返回类型不同而参数相同是编译错误不允许。重载的核心是参数列表必须不同。静态方法能被重写吗不能。静态方法是类级别的可以被隐藏Hide但不是重写。子类定义同名静态方法调用时取决于引用类型而非运行时对象。重载同类、同名、不同参编译时决定重写父子、同名、同参、改实现运行时决定什么是抽象类不能实例化不能new你无法直接创建抽象类的对象。比如你定义了abstract class Animal你不能写new Animal()因为“动物”这个概念太抽象没有具体形态。可能有抽象方法抽象方法只有声明没有方法体比如abstract void speak();。这些“未完成”的工作必须由子类去实现重写。所以必须有一个具体的子类去继承这个抽象类完成抽象方法然后才能创建子类的对象来使用。抽象类是一种半成品的类用来作为其他类的模板或基类。它可能有一部分方法已经实现好了共用的还有一部分方法只定义了“签名”但没有写具体实现代码抽象方法需要子类去补全。特点用abstract关键字修饰不能直接创建对象因为它不完整缺少一些方法的实现通常用于表达“一类事物”的上层概念如“动物”、“图形”而不具体指代某个实物例子java abstract class Animal { // 抽象类 String name; void eat() { // 普通方法有实现 System.out.println(吃东西); } abstract void speak(); // 抽象方法没有方法体必须由子类实现 }抽象类 vs 普通类对比维度抽象类普通类能否实例化new❌ 不能✅ 能能否包含抽象方法✅ 能可以有0~多个❌ 不能所有方法必须有实现能否包含普通方法✅ 能✅ 能能否有构造方法✅ 能供子类调用✅ 能能否有成员变量✅ 能✅ 能子类必须做的事必须实现所有抽象方法除非子类也是抽象类可选普通方法可重写也可不重写关键字abstract classclass设计目的作为基类定义通用模板强制子类实现某些行为直接描述具体对象拿来即用关键澄清抽象类可以没有抽象方法吗可以。一个抽象类也可以所有方法都有实现即没有抽象方法。但是即使它没有抽象方法只要被abstract修饰仍然不能new对象。比如java abstract class Base { // 有abstract但无抽象方法 void doSomething() { System.out.println(做某事); } } // 仍然不能 new Base();这种情况下抽象类主要是为了禁止直接实例化强制使用者必须通过子类使用。抽象类的作用提供公共代码复用将多个子类共用的属性、方法写在抽象类中避免重复。强制子类实现特定行为通过抽象方法确保每个子类都有自己版本的实现比如每个动物必须有speak()方法。限制实例化有些类在业务上就不应该有“实例”比如“动物”是一个概念不是具体一只猫或狗用抽象类表达更准确。抽象类和接口对比维度抽象类 (Abstract Class)接口 (Interface)关键字abstract classinterface继承/实现子类使用extends继承实现类使用implements实现多继承/多实现❌ 不支持多继承一个类只能继承一个抽象类✅ 支持多实现一个类可以实现多个接口构造方法✅ 可以有供子类调用❌ 不能有成员变量✅ 可以有各种类型的成员变量实例变量、静态变量默认public static final即常量必须显式初始化普通方法✅ 可以有具体实现的方法Java 8 之前❌ 不能有Java 8✅ 可以用default或static写有方法体的方法访问修饰符方法可以是public、protected、private默认且强制为publicJava 9 允许private方法设计意图代码复用模板模式用于定义一类事物的共同特征行为规范解耦用于定义一类事物能做什么接口的设计初衷是定义行为契约能做什么而不是描述对象的状态有什么属性。所以接口中不能有实例成员变量非static的成员变量。抽象类构造器的定义定义方式与普通类完全相同。java public abstract class Animal { private String name; private int age; // 抽象类的构造器 public Animal(String name, int age) this.name name; // 把参数 name 的值赋给成员变量 name this.age age; // 把参数 age 的值赋给成员变量 age System.out.println(Animal 构造器被调用); } public abstract void speak(); }核心区别谁来调用它这是与普通类最本质的区别。普通类构造器直接通过new关键字调用用来创建自己的实例。Person p new Person(张三, 20); // 调用 Person 的构造器抽象类不能通过new调用。它的构造器是在子类创建对象时由子类构造器通过super()隐式或显式地调用。public class Dog extends Animal { private String breed; public Dog(String name, int age, String breed) { super(name, age); // 显式调用父类抽象类的构造器 this.breed breed; } Override public void speak() { System.out.println(汪汪); } } // 使用 public class Main { public static void main(String[] args) { // Animal a new Animal(无名, 0); // ❌ 编译错误抽象类不能被实例化 Dog dog new Dog(旺财, 3, 金毛); // ✅ 会先调用 Animal 的构造器再调用 Dog 的构造器 } } }运行层面创建对象 赋初值从JVMJava虚拟机运行的角度看new Person(张三,20)这一步其实做了两件紧密相连的事在内存中划出一块空间创建出一个空的对象所有成员变量都是默认值比如namenullage0。调用构造方法把你写的赋值代码this.name name执行一遍把具体的值填进去。所以构造方法更像是在“创建好的空对象基础上把具体值填进去”。不过在日常理解中直接认为“构造方法负责创建并初始化对象”完全没问题。补充一个小细节如果没有写构造方法如果一个类你没有写任何构造方法编译器会自动赠送一个无参构造方法比如public Person() {}。这个“看不见”的构造方法什么都不做所以成员变量还是保持JVM给的默认初始值数字类型0booleanfalse引用类型如Stringnull构造器构造方法就是用来给成员变量赋初始值的特殊方法它在new对象时被自动调用保证对象一创建出来就处于一个合理的初始状态。接口可以包含构造函数吗核心原因构造函数用于“创建对象”而接口不能被实例化构造函数的唯一目的在new创建对象时被调用用来初始化对象的成员变量、完成对象创建前的准备工作。接口的特性接口不能被new实例化。你永远写不出new 某个接口()这样的代码。既然接口永远不会有“被创建对象”的那一刻那它的构造函数就永远没有机会被调用。一个永远无法被调用的方法在语法设计上就是无意义的所以 Java 直接禁止接口中包含构造函数。对比抽象类可以有构造函数虽然它也不能被new你可能会有疑问抽象类也不能被new为什么它能有构造函数抽象类接口能否被new实例化❌ 不能❌ 不能能否有构造函数✅ 能❌ 不能构造函数谁调用子类构造器通过super()调用——没有子类调用因为接口没有构造器链的概念关键差异抽象类的构造函数是给子类用的。子类对象被创建时会先调用父类抽象类的构造函数完成从父类继承来的那部分成员变量的初始化。而接口没有成员变量只能有public static final常量也没有“继承父类数据”的概念所以根本不需要、也没有地方可以安放一个构造函数。补充使用抽象类定义一个抽象类实现该接口在抽象类的构造函数中做初始化。然后具体类继承这个抽象类。可以实现接口层面的初始化。接口中的default方法Java 8 之后你可以在接口中定义一个default初始化方法比如default void init()然后要求实现类在适当的时候调用它。但这种方式是“主动调用”不是构造函数那种“自动调用”结语如果对你有帮助请点赞关注收藏你的支持就是我最大的鼓励