当前位置: 首页 > news >正文

Java抽象类、接口和内部类介绍

目录

一、抽象类

1. 基本概念

2. 特点

3. 语法格式

二、抽象方法

1. 基本概念

2. 特点

3. 语法格式

三、接口

1. 基本概念

2. 语法格式

3. 核心特性

4. 接口和类之间的关系

(1) 类与接口的实现关系

(2) 类与接口的依赖关系

(3) 接口与接口的继承关系

5. 接口与抽象类的区别

6. 接口的演进

(1)默认方法(default method)

(2)静态方法(static method)

(3)私有方法(private method)

7. 适配器设计模式

(1)使用场景

(2)使用步骤

四、类的五大成员

五、内部类

1. 成员内部类(Member Inner Class)

(1)基本概念

(2)创建对象的方式

①直接创建方式

②通过外部类方法获取

2. 静态内部类(Static Inner Class)

(1)基本概念

(2)创建对象的方式

①直接通过外部类名创建(最常用方式)

②通过外部类方法返回静态内部类实例

3. 局部内部类(Local Inner Class)

基本概念

4. 匿名内部类(Anonymous Inner Class)

(1)基本概念

(2)核心组成部分

①实例化操作符

②父类/接口声明

③构造参数列表

④类体定义块

⑤终结分号

5. 内部类的优点

6. 内部类的缺点


一、抽象类

1. 基本概念

抽象类(abstract class)是Java中一种特殊的类,它不能被实例化,只能被继承。抽象类的主要作用是为其子类提供统一的接口和公共属性集合,是面向对象编程中实现多态性的重要手段。

2. 特点

  • 禁止实例化:抽象类不能使用 new 关键字来创建对象。这是因为抽象类通常代表着一种不完整的概念,它是为了被继承而设计的,所以不能直接实例化。

  • 方法类型多样:抽象类中既可以有抽象方法,也可以有具体实现的非抽象方法。需要注意的是,如果一个类包含了抽象方法,那么这个类必然是抽象类。

  • 强制抽象修饰:要声明一个抽象类,必须在类声明前添加 abstract 关键字,以此明确该类的抽象性质。

  • 具备构造方法:尽管抽象类本身不能实例化,但它可以包含构造方法。这些构造方法在创建子类对象时发挥作用,用于给从父类继承来的属性赋值。子类可以通过 super() 调用父类的构造方法。

  • 包含成员变量:抽象类中可以包含成员变量,这些变量既可以是普通变量,也可以是静态变量,为类的功能实现提供数据支持。

  • 子类实现要求:抽象类的子类面临两种选择。其一,子类需要重写抽象类中的所有抽象方法,从而成为一个具体的类,具备创建对象的能力;其二,如果子类没有重写所有抽象方法,那么子类自身也必须被声明为抽象类,同样不能创建对象。

3. 语法格式

 public abstract class Animal {// 成员变量private String name;​// 构造方法public Animal(String name) {this.name  = name;}​// 具体方法public void sleep() {System.out.println("Sleeping...");}​// 抽象方法public abstract void animalSound();}

二、抽象方法

1. 基本概念

抽象方法(abstract method)是一种只有声明没有实现的方法,使用abstract关键字修饰,必须存在于抽象类或接口中。

2. 特点

  • 没有方法体:只有方法声明,以分号结束。

  • 必须存在于抽象类或接口中:普通类不能包含抽象方法。

  • 子类必须实现:除非子类也是抽象类。

  • 不能是private或static:因为需要被子类重写。

  • 不能是final:final方法不能被重写。

3. 语法格式

 public abstract class Shape {// 抽象方法public abstract double calculateArea();​// 具体方法public void display() {System.out.println("Displaying shape...");}}

三、接口

1. 基本概念

Java接口( Interface )是一种引用数据类型,它定义了一组方法的声明,是方法特征的集合。接口只有方法的特征而没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为。

2. 语法格式

 public interface 接口名称 {// 常量// 抽象方法// 默认方法(Java 8+)// 静态方法(Java 8+)// 私有方法(Java 9+)}

3. 核心特性

  • 不可实例化:接口不允许使用 new 运算符来创建实例。这是因为接口代表的是一种规范或契约,并非具体的实现,所以无法直接实例化。

  • 常量定义:接口内定义的变量默认具有 public static final 属性,这意味着它们是公开的、静态的且不可变的常量,在整个程序运行过程中保持固定值。

  • 抽象方法:接口里的方法默认被视为 public abstract 方法,在定义时可以省略这两个修饰符。这种设计使得接口专注于定义方法的签名,而不涉及具体实现。

  • 多继承支持:Java 中的类可以同时实现多个接口,这一特性有效弥补了 Java 单继承机制的局限性,让类能够同时具备多个接口所定义的行为。

  • 子类实现要求:接口的子类有两种选择。若子类不想成为抽象类,就必须重写接口中的所有抽象方法;若子类自身声明为抽象类,则无需完全实现这些抽象方法。

  • 默认方法:自 Java 8 起,接口开始支持默认方法(使用 default 关键字声明)。默认方法可以包含具体的方法体,为接口提供了一定的实现逻辑,同时不影响已有的实现类。

  • 静态方法:同样从 Java 8 开始,接口支持定义静态方法。这些静态方法可以直接通过接口名调用,无需创建实现类的实例。

  • 私有方法:Java 9 进一步增强了接口的功能,引入了私有方法。私有方法仅供接口内部使用,用于封装一些通用的逻辑,提高代码的复用性和可维护性。

4. 接口和类之间的关系

(1) 类与接口的实现关系
  • 类通过implements关键字实现接口,这要求类必须为接口中定义的所有方法提供具体实现。一个类仅能继承一个父类,但却可以同时实现多个接口,以此实现功能的多重扩展。

  • 若一个类无法完全实现接口中所有方法,该类必须声明为抽象类。抽象类允许将未实现的接口方法继续留作抽象方法,待子类进一步实现 。

(2) 类与接口的依赖关系
  • 类通过实现接口来扩展自身功能,而接口则定义了类必须实现的行为规范。

  • 类与接口的依赖关系通常表现为类需要实现接口以满足特定的规范或需求,而接口则为类提供了一种标准化的接口。

(3) 接口与接口的继承关系
  • 接口之间支持通过extends关键字建立继承关系。当一个接口继承另一个接口时,将自动获得被继承接口的所有方法与属性定义,从而实现代码的复用与功能的逐步扩展,显著提升开发效率。

  • 一个接口可以继承多个接口,而一个类只能继承一个接口。

5. 接口与抽象类的区别

特性接口抽象类
实例化不能不能
方法实现Java 8前只能有抽象方法可包含具体方法和抽象方法
变量只能是public static final普通变量和静态变量
构造方法不能有可以有
多继承支持多实现单继承
设计理念"like-a"关系"is-a"关系
版本兼容添加新方法会破坏现有实现添加具体方法不影响子类

6. 接口的演进

Java 8之前:只能包含抽象方法和常量,所有方法都是 public abstract ,所有变量都是 public static final

Java 8:引入默认方法和静态方法,默认方法使用 default 关键字修饰,静态方法可以直接通过接口调用。

Java 9:引入私有方法,支持接口方法的私有实现。

(1)默认方法(default method)

定义:默认方法允许在接口中提供带有实现的方法体。使用 default 关键字修饰,默认方法会被自动继承,实现类无需显式重写即可直接调用。

语法格式

 interface MyInterface {default void print() {System.out.println("Hello, World!");}}​class MyClass implements MyInterface {public void test() {print(); // 直接调用默认方法}}

特点

  • 默认方法必须使用 default 关键字进行修饰,并且其访问权限默认是 public,在实际编写代码时可以省略不写。

  • 实现类能够直接调用默认方法,也可以自行决定是否对其进行重写,重写并非强制要求。若选择重写,在重写时需去掉 default 关键字。

  • 当一个类实现了多个接口,而这些接口中存在同名的默认方法时,该类必须对同名方法进行重写,以此来消除方法调用的歧义。

  • 默认方法的引入有效解决了接口升级过程中可能出现的兼容性问题。由于实现类无需进行修改就能直接使用接口新增的默认方法,从而大大降低了接口升级对现有代码的影响。

(2)静态方法(static method)

定义:静态方法允许在接口中定义独立于实现类的方法,仅属于接口本身。使用static关键字修饰,静态方法只能通过接口名调用。

语法格式

 interface MyInterface {static void log(String message) {System.out.println(message);}}​public class Test {public static void main(String[] args) {MyInterface.log("日志信息"); // 通过接口名调用静态方法}}

特点

  • 静态方法必须使用 static 关键字进行修饰,并且其访问权限默认是 public,在实际编写代码时可以省略不写。

  • 静态方法不能被实现类覆盖或继承,仅能通过接口名调用。

  • 静态方法通常用于封装与接口相关的辅助功能,降低对第三方类的依赖。

(3)私有方法(private method)

定义:私有方法是JDK 9引入的新特性,允许在接口中定义私有的实例方法。私有方法只能在接口内部被其他方法调用,不能被实现类直接访问。

语法格式

 interface MyInterface {default void print() {privateMethod(); // 调用私有方法}​private void privateMethod() {System.out.println("私有方法");}}​class MyClass implements MyInterface {public void test() {print(); // 调用默认方法,间接调用私有方法}}

特点

  • 私有方法必须使用private修饰,默认为private

  • 私有方法不能被实现类覆盖或继承,仅能在接口内部使用。

  • 私有方法主要用于封装接口中的通用逻辑,提高代码的可维护性和封装性。

7. 适配器设计模式

(1)使用场景

在实际开发中,当一个接口包含大量抽象方法,而我们仅需使用其中一部分时,适配器设计模式便能展现出显著优势。

(2)使用步骤

以下为运用适配器设计模式的详细步骤:

  1. 创建中间适配器类:编写一个名为 XXXAdapter 的中间类,让它实现对应的接口。该中间类充当接口与真正实现类之间的桥梁,起到承上启下的连接作用。

  2. 空实现接口方法:在 XXXAdapter 类里,对接口中的所有抽象方法进行空实现。这样做的目的是为后续的子类提供一个基础模板,让子类无需再去实现那些不需要的方法,减轻开发负担。

  3. 实现具体功能:创建真正的实现类,并让其继承 XXXAdapter 中间类。接着在这个实现类中,重写那些我们实际需要使用的方法,以此实现具体的业务逻辑。

  4. 避免实例化:为防止其他类创建 XXXAdapter 适配器的对象,可使用 abstract 关键字将中间的适配器类修饰为抽象类。这样该类便无法被实例化,只能作为父类供子类继承,确保了设计模式的正确运用。

  5. 处理继承关系:若实现类已有父类,可让 XXXAdapter 继承该父类,以确保类的继承结构合理且满足实际需求。

四、类的五大成员

类的五大成员共同构成了一个完整的Java类,分别负责管理对象的状态(字段)、行为(方法)、初始化(构造器和代码块)以及复杂结构设计(内部类)。

成员作用关键特点
字段(Field / 成员变量)描述对象状态privatestaticfinal
方法(Method)定义对象行为重载、重写
构造器(Constructor)初始化对象与类同名、无返回值
代码块(Block)初始化逻辑static{}(静态)、{}(实例)
内部类(Inner Class)增强封装性/多继承四种类型

五、内部类

Java中的内部类(Inner Class)是定义于其他类(外部类)内部的特殊类结构。这种类所描述的事物本质上是外部类的组成部分,无法脱离外部类独立存在与使用,所以内部类单独出现没有任何意义。内部类拥有独特的访问权限优势,能够直接访问外部类的所有成员,包括被 private 修饰的私有成员,这一特性不仅强化了代码的封装性,将紧密关联的逻辑聚合在同一作用域内,还赋予程序设计更高的灵活性。不过,访问权限具有单向性:若外部类需要访问内部类的成员变量或方法,则必须先实例化内部类对象,通过对象引用来完成访问操作。

根据定义位置和使用场景,Java中的内部类可以分为以下四种类型:

1. 成员内部类(Member Inner Class)

(1)基本概念

成员内部类可以继承外部类,并且可以被外部类实例化后访问。成员内部类的创建过程严格受制于外部类实例,无法通过 new 内部类() 的常规方式直接实例化。在 JDK 16 之前,成员内部类受限于设计规则,无法定义静态变量;直到 JDK 16 后,这一限制被解除,开发者得以在成员内部类中定义静态变量。此外,成员内部类支持使用多种修饰符(如 privateprotectedpublic 等),以灵活控制其访问范围。

 public class OuterClass {private int x = 10;public class InnerClass {public void print() {System.out.println(x); // 访问外部类的私有变量}}}
(2)创建对象的方式

创建成员内部类对象主要有以下两种方式:

①直接创建方式

通过外部类实例创建内部类对象,语法格式为:

 外部类.内部类 变量名 = new 外部类().new 内部类();

或分步创建:

 外部类 outer = new 外部类();外部类.内部类 inner = outer.new 内部类();

示例:

 public class Outer {class Inner {}}​// 创建内部类对象Outer.Inner inner = new Outer().new Inner();
②通过外部类方法获取

在外部类中定义方法返回内部类实例(如果内部类是private修饰的,只能通过此方式获取):

 public class Outer {private class Inner {}public Inner getInnerInstance() {return new Inner();}}​// 使用方式Outer outer = new Outer();Outer.Inner inner = outer.getInnerInstance();

2. 静态内部类(Static Inner Class)

(1)基本概念

静态内部类是定义在外部类内部的静态类,它是一种特殊的成员内部类。静态内部类能够直接访问外部类的静态成员变量与方法(小技巧:静态的成员都可以直接使用 类名.XXX 直接获取);若需操作外部类的非静态成员,则必须显式创建外部类的实例。与成员内部类不同,静态内部类的实例化过程独立于外部类实例,即使外部类尚未实例化,也可直接通过 外部类名.静态内部类名 的方式创建静态内部类对象,这种特性赋予其更高的独立性与灵活性。

 public class OuterClass {private static int x = 10;public static class StaticInnerClass {public void print() {System.out.println(x); // 访问外部类的静态变量}}}
(2)创建对象的方式
①直接通过外部类名创建(最常用方式)

这是最直接的创建方式,因为静态内部类不依赖于外部类的实例。

 外部类.内部类 变量名 = new 外部类.内部类();
②通过外部类方法返回静态内部类实例

这种方式适合需要封装创建逻辑的场景。

 // 外部类中定义方法public static StaticInnerClass getInnerInstance() {return new StaticInnerClass();}​// 使用方式OuterClass.StaticInnerClass inner = OuterClass.getInnerInstance();

3. 局部内部类(Local Inner Class)

基本概念

局部内部类是一种定义在方法体或代码块内部的非静态类,其作用域严格限定在所在的方法或代码块内。局部内部类无法通过外部类进行实例化,仅能在其定义的内部环境(比如方法内部)中创建对象并使用。在访问权限方面,局部内部类可直接访问外部类的所有成员,也能访问所在方法内的局部变量。不过,这些被访问的局部变量需满足有效最终变量的要求,即变量在初始化后不再被修改。局部内部类中不允许定义静态成员变量和方法,也不能使用 privateprotectedpublic 等访问修饰符。

 class OuterClass {void outerMethod() {// 局部内部类定义在方法内class LocalInnerClass {// 成员变量和方法void innerMethod() {System.out.println("Local Inner Class Method");}}​// 在方法内创建局部内部类的实例并调用LocalInnerClass inner = new LocalInnerClass();inner.innerMethod();}}

4. 匿名内部类(Anonymous Inner Class)

(1)基本概念

匿名内部类是一种没有显式命名的特殊内部类,其定义位置灵活,既可以置于外部类的成员位置,也能够出现在方法或代码块等局部区域,通常在需要快速实现接口或继承抽象类时使用。它没有类名,必须通过 new 关键字直接创建实例,并且必须在创建时完成接口方法的实现或抽象类方法的重写。此外,匿名内部类同样受到严格的限制,不允许定义静态成员变量和方法,这也决定了它仅适用于实现临时性、轻量级的功能需求。

 // 定义一个接口,包含一个抽象方法print()interface MyInterface {void print();  // 抽象方法声明,需要实现类具体实现}​// 外部类定义public class OuterClass {// 外部类的实例方法public void someMethod() {// 创建匿名内部类实例并实现接口MyInterface myObject = new MyInterface() {  // 匿名内部类开始// 实现接口中的抽象方法public void print() {// 方法具体实现System.out.println("Anonymous Inner Class");}};  // 匿名内部类结束,注意结尾的分号// 调用匿名内部类实现的方法myObject.print();  // 输出: Anonymous Inner Class}}
(2)核心组成部分
①实例化操作符

new 关键字标志匿名类的实例化起点。

②父类/接口声明

必须指定继承的类或实现的接口(二选一)。

  • 类继承:SuperClass(args)

  • 接口实现:InterfaceName()

③构造参数列表

圆括号()包含父类构造参数(接口实现则为空括号)。

④类体定义块

花括号{}内包含:

  • 成员变量声明

  • 实例方法实现(必须实现所有抽象方法)

  • 实例初始化块

  • 局部内部类(嵌套使用)

⑤终结分号

匿名类作为表达式必须以;结尾。

5. 内部类的优点

  • 提供更好的封装性:内部类可以直接访问外部类的私有成员,而外部类无法访问内部类的实现细节。

  • 支持多继承:Java不支持多继承,但通过内部类可以实现类似的效果,例如一个内部类可以继承多个接口或抽象类。

  • 简化代码:在某些场景下,使用内部类可以使代码更加简洁和清晰。

6. 内部类的缺点

  • 性能开销:由于内部类需要引用外部类实例,可能会增加内存消耗和运行时开销。

  • 可读性问题:过多使用内部类可能导致代码结构复杂,降低可读性。

相关文章:

  • Spring AI Alibaba Graph基于 ReAct Agent 的天气预报查询系统
  • 解决 Arduino IDE 2.3.6 在 Windows 上无法启动:缺少 Documents 文件夹与注册表路径错误
  • Spring AOP 事务
  • 【Linux专栏】zip 多个文件不带路径
  • 2025年渗透测试面试题总结-拷打题库09(题目+回答)
  • Windows1909,21H2哪个版本更稳定
  • 小刚说C语言刷题——1039 求三个数的最大数
  • 1️⃣4️⃣three.js_Stats性能监视器
  • 机器学习中,什么叫监督学习?什么叫非监督学习?
  • 25.解决中医知识问答删除历史对话功能后端处理请求时抛出异常
  • 【大数据、数据开发与数据分析面试题汇总(含答案)】
  • OpenCV训练题
  • 【Redis】Redis 特性
  • L1-1、Prompt 是什么?为什么它能“控制 AI”?
  • 爱普生TG-5006CG成为提升5G RedCap时钟同步精度的理想选择
  • ECA 注意力机制:让你的卷积神经网络更上一层楼
  • 【Pandas】pandas DataFrame sub
  • FreeRTOS互斥信号量解决优先级翻转实战教程
  • 大模型中超参数TopK是什么
  • 批量创建同名文件夹并整理文件至对应文件夹
  • 第三轮上海餐饮消费券本周五起报名,核销时间延长至6月2日
  • 大学2025丨浙大哲学院院长王俊:文科的价值不在于直接创造GDP
  • 国家新闻出版署:4月共118款国产网络游戏获批
  • 上海又现昆虫新物种:体长仅1.5毫米,却是凶猛的捕食者
  • 视觉周刊|第五届中国国际消费品博览会展现全球合作新格局
  • 人民日报:对科研不端行为加大惩处力度,让造假成本远高于收益