抽象类 接口 内部类

抽象类

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

类比

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

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

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();
        }
    );
}

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

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

实用建议

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

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

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

相关推荐
叼烟扛炮29 分钟前
C++ 知识点08 类与对象
开发语言·c++·算法·类和对象
你不是我我7 小时前
【Java 开发日记】HTTP3 性能更好,为什么内网微服务依然多用 HTTP2?HTTP2 内网优势是什么?
java·开发语言·微服务
雪碧聊技术7 小时前
大模型爆火!Java后端如何抓住Agent全栈开发的风口
java·大模型·agent·全栈开发
tjl521314_217 小时前
04C++ 名称空间(Namespace)
开发语言·c++
赏金术士8 小时前
Kotlin 数据流与单双向绑定
android·开发语言·kotlin
逻辑驱动的ken8 小时前
Java高频面试场景题25
java·开发语言·深度学习·面试·职场和发展
AI人工智能+电脑小能手9 小时前
【大白话说Java面试题】【Java基础篇】第32题:Java的异常处理机制是什么
java·开发语言·后端·面试
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ10 小时前
通过java后端代码来实现给word内容补充格式文本内容控件,以及 设置控件的标记和标题
java·c#·word
無限進步D11 小时前
Java 面向对象高级 接口
java·开发语言