抽象类 接口 内部类

抽象类

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

类比

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

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

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

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

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

实用建议

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

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

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

相关推荐
skilllite作者18 小时前
SkillLite 架构优化分析报告:项目开发日记
大数据·开发语言·后端·架构·rust·rust沙箱
zore_c18 小时前
【C++】C++——类的默认成员函数(构造、析构、拷贝构造函数)
java·c语言·c++·笔记·算法·排序算法
我登哥MVP18 小时前
【SpringMVC笔记】 - 4 - 三个域对象
java·spring boot·spring·servlet·tomcat·maven·intellij-idea
Seven9718 小时前
【从0到1构建一个ClaudeAgent】协作-Agent团队
java
进击的荆棘18 小时前
C++起始之路——AVL树的实现
开发语言·数据结构·c++·stl·avl
郝学胜-神的一滴18 小时前
[系统设计] 新鲜事系统:写扩散与读扩散的实现与对比
java·设计模式·php·软件构建·需求分析·软件设计·系统设计
进击的荆棘18 小时前
C++起始之路——红黑树的实现
开发语言·数据结构·c++·stl·红黑树
疯狂成瘾者19 小时前
LangChain4j ApacheTikaDocumentParser:多格式文档接入的统一入
java·langchain4j
庞轩px20 小时前
第三篇:泛型深度解析——类型擦除与通配符的奥秘
java·编译·泛型·类型擦除
W.A委员会1 天前
JS原型链详解
开发语言·javascript·原型模式