抽象类 接口 内部类

抽象类

一句话 :抽象类是不能被实例化的类,它专门用来当"模板",让子类去继承。

类比

  • 你设计一张"动物"的蓝图,上面写着"所有动物都要会叫",但你不具体写怎么叫。

  • 这张蓝图就是抽象类,你没法直接拿它造一只动物,只能用它来造具体的动物(狗、猫).相当于我只是给了我的子类一个规定,如果我的子类要做一个什么样的动作,我在父类里面规定,他做这个动作,需要用这样的方法来去写。

java 复制代码
// 抽象类
abstract class Order {
    protected String orderId;  // 公共字段
    protected double amount;

    // 公共方法(已实现)
    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    // 抽象方法:必须由子类实现
    public abstract void pay();
}

// 子类
class AlipayOrder extends Order {
    @Override
    public void pay() {
        System.out.println("使用支付宝支付:" + amount);
    }
}

class WechatOrder extends Order {
    @Override
    public void pay() {
        System.out.println("使用微信支付:" + amount);
    }
}

// 使用
Order order1 = new AlipayOrder();
order1.pay();  // 输出:使用支付宝支付

接口

接口是Java中的一种引用类型,它定义了一组方法规范(方法名、参数、返回类型),但不提供具体实现。接口表示"能做什么"(能力),而不是"是什么"。

  • 接口中的方法默认是 public abstract

  • 接口中的变量默认是 public static final(常量)】

    java 复制代码
    // 定义接口
    public interface Payment {
        boolean pay(double amount);   // 方法名、参数、返回类型,没有方法体
        boolean refund(String orderId);
    }

接口.Java文件的位置

java 复制代码
src/
└── com/example/order/
    ├── controller/
    │   └── OrderController.java
    ├── service/
    │   ├── OrderService.java       // 接口
    │   └── impl/
    │       └── OrderServiceImpl.java // 实现类
    ├── repository/
    │   └── OrderRepository.java    // 接口(Spring Data JPA)
    └── entity/
        └── Order.java

接口的具体实现

1. 实现接口的关键字:implements

一个类通过 implements 关键字来实现接口,并且必须重写接口中定义的所有抽象方法(除非该类本身是抽象类)。

java 复制代码
public class Alipay implements Payment {
    @Override
    public boolean pay(double amount) {
        // 具体的支付宝支付逻辑
        System.out.println("支付宝支付:" + amount + "元");
        return true;
    }
    
    @Override
    public boolean refund(String orderId) {
        System.out.println("支付宝退款,订单号:" + orderId);
        return true;
    }
}
2. 使用接口(面向接口编程)
java 复制代码
public class OrderService {
    private Payment payment;   // 用接口类型声明变量
    
    // 通过构造方法注入具体实现(Spring中会用@Autowired自动注入)
    public OrderService(Payment payment) {
        this.payment = payment;
    }
    
    public void checkout(double amount) {
        payment.pay(amount);   // 调用接口方法,实际执行的是实现类的代码
    }
}
3. 多态效果
java 复制代码
Payment p1 = new Alipay();
Payment p2 = new WechatPay();

p1.pay(100);   // 执行支付宝支付
p2.pay(100);   // 执行微信支付

同一个接口类型,不同的实现类,调用同一个方法产生不同的行为------这就是多态在接口中的体现。

内部类(Inner Class)

内部类就是定义在另一个类内部的类。它和普通类最大的区别是:它可以访问外部类的所有成员(包括私有成员)。

一、为什么需要内部类

  1. 逻辑上的归属:有些类天生就是为另一个类服务的,比如"汽车"的"发动机"类,放在外部显得多余,放在内部更合理。

  2. 增强封装:内部类可以访问外部类的私有成员,但不对外暴露。

  3. 代码组织:让结构更清晰,避免一个包下堆满几十个类文件。

二、内部类的四种类型

类型 关键字 特点
成员内部类 无 static 作为外部类的成员,可以访问外部类的所有成员
静态内部类 static 不持有外部类的引用,只能访问外部类的静态成员
局部内部类 定义在方法内部,只能在方法内使用
匿名内部类 没有类名,通常用于临时实现接口或抽象类

三、代码示例

1. 成员内部类
java 复制代码
public class Outer {
    private String name = "外部类";
    
    // 成员内部类
    class Inner {
        public void show() {
            System.out.println("访问外部类的私有属性:" + name);
        }
    }
    
    public void test() {
        Inner inner = new Inner();
        inner.show();
    }
}

// 使用
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();  // 需要通过外部类实例创建
2. 静态内部类
java 复制代码
public class Outer {
    private static String staticName = "静态属性";
    
    // 静态内部类
    static class StaticInner {
        public void show() {
            System.out.println("访问外部类的静态属性:" + staticName);
            // 不能访问外部类的非静态成员
        }
    }
}

// 使用
Outer.StaticInner inner = new Outer.StaticInner();  // 不需要外部类实例
3. 局部内部类
java 复制代码
public class Outer {
    public void method() {
        int localVar = 10;
        
        // 局部内部类(定义在方法里)
        class LocalInner {
            public void show() {
                System.out.println("局部内部类,localVar = " + localVar);
            }
        }
        
        LocalInner inner = new LocalInner();
        inner.show();
    }
}
4. 匿名内部类(最常用,尤其在框架中)
java 复制代码
// 场景:临时实现一个接口
Runnable task = new Runnable() {
    @Override
    public void run() {
        System.out.println("匿名内部类实现的线程任务");
    }
};

// 或者使用 Lambda(Java 8+,匿名内部类的简化版)
Runnable task2 = () -> System.out.println("Lambda 表达式");

四、你在框架中会看到的内部类

java 复制代码
// 写测试类时经常这么用
@Test
public void test() {
    // 匿名内部类实现回调
    restTemplate.execute("http://api.example.com", HttpMethod.GET, 
        request -> {
            // 匿名内部类:设置请求头
            request.getHeaders().set("Authorization", "token");
        },
        response -> {
            // 匿名内部类:处理响应
            return response.getBody();
        }
    );
}

你不需要刻意去写内部类,但需要能看懂这种写法,尤其是在看框架源码或别人写的代码时。

类型 是否需要外部类实例 能否访问外部类非静态成员
成员内部类 ✅ 需要 ✅ 能
静态内部类 ❌ 不需要 ❌ 不能
局部内部类 看情况 ✅ 能
匿名内部类 看情况 ✅ 能

实用建议

  • 日常开发中最常用的是匿名内部类(尤其是写监听器、回调时)

  • 静态内部类比较常用(因为不持有外部类引用,不会造成内存泄漏)

  • 成员内部类和局部内部类用得较少,能看懂即可

相关推荐
RMB Player几秒前
Spring Boot 集成飞书推送超详细教程:文本消息、签名校验、封装工具类一篇搞定
java·网络·spring boot·后端·spring·飞书
努力中的编程者1 分钟前
二叉树(C语言底层实现)
c语言·开发语言·数据结构·c++·算法
重庆小透明6 分钟前
【搞定面试之mysql】第三篇 mysql的锁
java·后端·mysql·面试·职场和发展
大尚来也13 分钟前
PHP 反序列化漏洞深度解析:从原理利用到 allowed_classes 防御实战
android·开发语言·php
RuoyiOffice14 分钟前
企业请假销假系统设计实战:一张表、一套流程、两段生命周期——BPM节点驱动的表单变形术
java·spring·uni-app·vue·产品运营·ruoyi·anti-design-vue
鹤旗15 分钟前
While语句,do-while语句,for语句
java·jvm·算法
雕刻刀16 分钟前
ERROR: Failed to build ‘natten‘ when getting requirements to build wheel
开发语言·python
qq_4160187216 分钟前
高性能密码学库
开发语言·c++·算法
小碗羊肉25 分钟前
【从零开始学Java | 第十八篇】BigInteger
java·开发语言·新手入门
宵时待雨28 分钟前
C++笔记归纳14:AVL树
开发语言·数据结构·c++·笔记·算法