乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Java概述与环境搭建

    • Java概述与环境搭建
    • Java语言概述
    • 解释型语言与编译型语言对比
    • JDK安装与配置
    • JDK、JRE、JVM 详解
    • HelloWorld程序详解
    • IDE 介绍
  • 第2章 标识符与基本数据类型

    • 章节导读
    • 变量概述
    • 常量概述
    • 基本类型与包装类
    • 字节型 byte
    • 短整型 short
    • 整型 int
    • 长整型 long
    • 单精度浮点型 float
    • 双精度浮点型 double
    • 字符型 char
    • 布尔型 boolean
    • 类型转换
  • 第3章 运算符与表达式

    • 章节导读
    • 算术运算符
    • 赋值运算符
    • 关系运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 运算符优先级
    • 表达式
  • 第4章 流程控制

    • 章节导读
    • 常见的程序运行流程
    • if-else 选择结构
    • switch 多分支选择
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
  • 第5章 数组

    • 章节导读
    • 一维数组
    • 多维数组
    • Arrays 工具类
  • 第6章 类与对象

    • 章节导读
    • 类与对象
    • 方法定义与调用
    • 构造方法
    • 封装
    • 访问修饰符
    • package 与 import
    • static 关键字
    • this 关键字
    • 参数传递 详解
    • 枚举
    • 成员内部类
    • 局部内部类
    • 静态内部类
    • 匿名内部类
  • 第7章 接口与继承

    • 章节导读
    • 继承
    • super 关键字
    • final 关键字
    • 多态
    • 向上转型与向下转型
    • 抽象类
    • 接口
    • 抽象类与接口对比
  • 第8章 注解

    • 章节导读
    • 注解基础
    • 元注解详解
    • 自定义注解
  • 第9章 常用类

    • 章节导读:Java 常用类
    • Object 类:万类之祖
    • 包装类:基本类型的对象化
    • String:不可变的字符串
    • StringBuffer:线程安全的可变字符串
    • StringBuilder:可变的字符串构建器
    • Math:数学运算工具类
    • Random:伪随机数生成器
    • 大数值运算 详解
    • 日期时间API 详解
  • 第10章 异常机制

    • 章节导读
    • 异常体系与分类
    • try-catch-finally
    • try-with-resources
    • throws 与 throw
    • 自定义异常
  • 第11章 泛型

    • 章节导读
    • 泛型基础
    • 通配符与PECS原则
    • 类型擦除
  • 第12章 集合框架

    • 章节导读
    • 集合框架概述
    • ArrayList
    • LinkedList
    • HashMap 详解
    • LinkedHashMap 详解
    • TreeMap 详解
    • HashSet
    • TreeSet 详解
    • TreeSet 与 Comparable
    • Collections 工具类详解
  • 第13章 IO流

    • 章节导读
    • IO流概述
    • 字节流
    • 字符流
    • 缓冲流
    • 转换流 详解
    • 序列化 详解
    • NIO与Files 详解
    • NIO与Files工具类
  • 第14章 多线程与并发

    • 第十六章 多线程与并发 —— 章节导读
    • 线程基础详解
    • synchronized 详解
    • Lock 与显式锁详解
    • volatile 详解
    • wait 与 notify 详解
    • ThreadLocal详解
    • 原子类详解
    • 并发工具类详解
    • 线程池详解
  • 第15章 反射

    • 章节导读
    • 反射概述与 Class 对象
    • Constructor 与对象创建
    • Field与Method详解
    • 反射应用详解
  • 第16章 JDK8新特性

    • 章节导读
    • Lambda 表达式
    • Stream API 基础
    • Stream API 高级详解
    • Optional 详解
    • 新日期时间API详解
  • 第17章 JDK9-11新特性

    • 章节导读
    • 模块化系统 — Project Jigsaw(JDK 9)
    • var 局部变量类型推断(JDK 10)
    • 集合工厂方法与增强(JDK 9 / 10 / 11)
    • 接口增强:private 方法(JDK 9)
    • Stream API 增强(JDK 9)
    • Optional 增强(JDK 9 / 10 / 11)
    • String 新增方法(JDK 11)
    • HTTP Client 与 Files 增强(JDK 11)
    • 直接运行 Java 源文件 — JEP 330(JDK 11)
  • 第18章 JDK12-17新特性

    • 章节导读
    • Switch 表达式(JDK 12 预览 / JDK 14 正式)
    • 文本块 Text Blocks(JDK 13 预览 / JDK 15 正式)
    • Records 记录类(JDK 14 预览 / JDK 16 正式)
    • 密封类 Sealed Classes(JDK 15 预览 / JDK 17 正式)
    • instanceof 模式匹配(JDK 14 预览 / JDK 16 正式)
    • Switch 模式匹配 — Pattern Matching for switch(JDK 17 预览 / JDK 21 正式)
    • Helpful NPE 与 String 增强(JDK 12 / JDK 14 / JDK 15)
    • Stream 增强(JDK 12 / JDK 16)
    • 日期时间增强 — Day Period 支持(JDK 16)
  • 第19章 JDK18-21新特性

    • 章节导读
    • 虚拟线程(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 序列集合(JDK 21 正式)
    • Switch 模式匹配(JDK 17 预览 / JDK 18 第二预览 / JDK 20 第四预览 / JDK 21 正式)
    • Record 模式匹配(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 未命名模式与变量(JDK 21 预览 / JDK 22 正式)
  • 第20章 JDK 22-25 新特性

    • 章节导读
    • 字符串模板(JDK 22 预览 / JDK 23 第二预览 / JDK 24 第三预览)
    • Stream Gatherers(JDK 22 预览 / JDK 24 第二预览)
    • 隐式声明类与实例方法(JDK 23 预览 / JDK 24 第二预览)
    • 原始类型模式匹配(JDK 24 预览)
  • 附录

    • Java 核心知识点
    • Java SE 专业术语
    • Java特性索引(JDK 8 → 25)

匿名内部类

小崔(后端开发):"白歌,这个new Runnable() { ... }是创建一个Runnable对象吗?接口不是不能实例化吗?"

白歌(架构师):"表面上是new Runnable(),实际是创建了一个实现Runnable接口的匿名类的实例。编译器会生成一个$1.class文件,你可以反编译看看——它是一个有名字的类(对 JVM 而言),只是对程序员来说'匿名'。"

朱璐(前端转 Java):"那 JDK 8 的 Lambda 表达式和匿名内部类是一样的吗?"

白歌:"不完全一样。Lambda 在字节码层面用的是 invokedynamic 指令,不生成 .class 文件;匿名内部类会生成独立的 .class 文件。作用域也不同——Lambda 里的 this 指向外部类,匿名内部类的 this 指向自身。这是面试极爱考的区分点。"


定义与语法

匿名内部类(Anonymous Inner Class) 是没有名字的内部类,它将类的定义和对象的创建合二为一。匿名内部类必须实现一个接口或继承一个类。

语法表格

要素说明
定义方式new 接口名() { } 或 new 类名(参数) { }
类名无(编译器自动生成 Outer$N)
构造方法不能定义构造方法(因为没有名字)
继承/实现只能继承一个类 或 实现一个接口(不能同时)
访问局部变量必须 final 或 effectively final
.class 文件名Outer$1.class、Outer$2.class...
静态成员不能有静态方法或静态字段(除编译期常量)
JDK 8 替代函数式接口可用 Lambda 表达式简化

基础语法示例

// ========== 实现接口 ==========
Runnable task = new Runnable() {     // 不是 new 接口,是 new 匿名类
    @Override
    public void run() {
        System.out.println("匿名内部类实现 Runnable");
    }
};

// ========== 继承类 ==========
Thread t = new Thread("飞翔-工作线程") {
    @Override
    public void run() {
        System.out.println(getName() + " 正在执行");
    }
};

// ========== 带参数构造 ==========
// 匿名内部类可以调用父类的带参构造方法
new ArrayList<String>(10) {{
    add("技术部");  // 实例初始化块
    add("市场部");
}};

深度原理分析:字节码揭秘

1. 编译器如何处理匿名内部类

编写以下代码:

public class Outer {
    public void test() {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类");
            }
        };
    }
}

编译后生成两个文件:

  • Outer.class
  • Outer$1.class → 就是那个匿名内部类

使用 javap -p Outer$1 查看:

final class Outer$1 implements Runnable {
    final Outer this$0;  // 持有外部类引用

    Outer$1(Outer);      // 构造方法接收外部类引用

    public void run();   // 实现的方法
}

2. 匿名内部类访问局部变量的字节码

public class Outer {
    public void test() {
        final String message = "Hello";  // 或 effectively final
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(message);  // 访问局部变量
            }
        };
    }
}

javap -p Outer$1:

final class Outer$1 implements Runnable {
    final String val$message;  // 拷贝的局部变量
    final Outer this$0;

    Outer$1(Outer, String);    // 构造方法接收局部变量值
}

3. 匿名内部类 vs Lambda:字节码层面的本质区别

// this 区分的经典对比
public class Outer {
    private String name = "Outer";

    public void test() {
        // 匿名内部类 —— this 指向匿名类自身
        Runnable anon = new Runnable() {
            private String name = "Anonymous";
            @Override
            public void run() {
                System.out.println(this.name);  // "Anonymous"
                System.out.println(Outer.this.name);  // "Outer"
            }
        };
        anon.run();  // 输出 Anonymous, Outer

        // Lambda —— this 指向外部类
        Runnable lambda = () -> {
            System.out.println(this.name);  // "Outer" —— this 是 Outer
            // System.out.println(Outer.this.name); // 这样写也行,但 this 就直接是 Outer
        };
        lambda.run();  // 输出 Outer, Outer
    }

    public static void main(String[] args) {
        new Outer().test();
    }
}

完整示例

示例一:飞翔科技事件通知系统

import java.util.ArrayList;
import java.util.List;

/**
 * 飞翔科技事件总线
 * 使用匿名内部类实现事件监听器注册
 */

// 事件接口
interface EventListener {
    void onEvent(String event);
}

// 事件总线
class EventBus {
    private List<EventListener> listeners = new ArrayList<>();

    // 注册监听器
    public void register(EventListener listener) {
        listeners.add(listener);
    }

    // 触发事件
    public void fireEvent(String event) {
        System.out.println("[EventBus] 触发事件: " + event);
        for (EventListener listener : listeners) {
            listener.onEvent(event);
        }
    }
}

// 部门服务
class DepartmentService {
    private String name;

    public DepartmentService(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    /**
     * 注册事件监听 —— 使用匿名内部类
     * 每个部门对事件有不同的响应逻辑
     */
    public void registerToBus(EventBus bus) {
        // ========== 匿名内部类:事件监听器 ==========
        bus.register(new EventListener() {
            @Override
            public void onEvent(String event) {
                // 可以访问外部类的 name 字段
                System.out.println("  [" + name + "] 收到事件: " + event);
                if (event.contains("紧急")) {
                    System.out.println("    ⚡ " + name + " 启动紧急响应流程");
                }
            }
        });
    }
}

public class EventSystemDemo {
    public static void main(String[] args) {
        EventBus bus = new EventBus();

        // 各部门注册监听
        DepartmentService tech = new DepartmentService("技术部");
        DepartmentService market = new DepartmentService("市场部");
        DepartmentService hr = new DepartmentService("人力资源部");

        tech.registerToBus(bus);
        market.registerToBus(bus);
        hr.registerToBus(bus);

        // 触发事件
        System.out.println("========== 飞翔科技事件通知系统 ==========");
        bus.fireEvent("系统维护通知:今晚22:00例行升级");
        System.out.println();
        bus.fireEvent("紧急:服务器宕机,请相关部门立即处理");

        // 查看匿名内部类文件命名
        System.out.println();
        System.out.println("匿名内部类示例类名: "
            + new EventListener() {
                @Override
                public void onEvent(String event) {}
              }.getClass().getName());
    }
}
运行输出:
========== 飞翔科技事件通知系统 ==========
[EventBus] 触发事件: 系统维护通知:今晚22:00例行升级
  [技术部] 收到事件: 系统维护通知:今晚22:00例行升级
  [市场部] 收到事件: 系统维护通知:今晚22:00例行升级
  [人力资源部] 收到事件: 系统维护通知:今晚22:00例行升级

[EventBus] 触发事件: 紧急:服务器宕机,请相关部门立即处理
  [技术部] 收到事件: 紧急:服务器宕机,请相关部门立即处理
    ⚡ 技术部 启动紧急响应流程
  [市场部] 收到事件: 紧急:服务器宕机,请相关部门立即处理
    ⚡ 市场部 启动紧急响应流程
  [人力资源部] 收到事件: 紧急:服务器宕机,请相关部门立即处理
    ⚡ 人力资源部 启动紧急响应流程

匿名内部类示例类名: EventSystemDemo$3

示例二:匿名内部类与Lambda的全面对比

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * 匿名内部类 vs Lambda 全面对比
 * 包含所有关键区分点:this 引用、外部变量遮蔽、字节码等
 */
public class LambdaVsAnonDemo {
    private String prefix = "[飞翔科技]";

    // ========== 函数式接口定义 ==========
    @FunctionalInterface
    interface StringProcessor {
        String process(String input);
    }

    // ========== 对比1:基本写法 ==========
    public void compareSyntax() {
        String input = "Hello World";

        // 匿名内部类方式(JDK 1.1+)—— 冗长
        StringProcessor anonProcessor = new StringProcessor() {
            @Override
            public String process(String s) {
                return prefix + " " + s.toUpperCase();
            }
        };

        // Lambda 方式(JDK 8+)—— 简洁
        StringProcessor lambdaProcessor = s -> prefix + " " + s.toUpperCase();

        System.out.println("===== 写法对比 =====");
        System.out.println("匿名内部类: " + anonProcessor.process(input));
        System.out.println("Lambda:     " + lambdaProcessor.process(input));
    }

    // ========== 对比2:this 引用(关键区分!)==========
    public void compareThisReference() {
        // 匿名内部类 —— this 指向匿名类实例
        Runnable anonRunnable = new Runnable() {
            @Override
            public void run() {
                // this 指向 Runnable 的匿名实现类
                System.out.println("匿名内部类 this 的 class: " + this.getClass().getName());
                // 需要 Outer.this 来访问外部类
                System.out.println("  外部类 prefix: " + LambdaVsAnonDemo.this.prefix);
            }
        };

        // Lambda —— this 指向外部类实例
        Runnable lambdaRunnable = () -> {
            // this 就是 LambdaVsAnonDemo 的实例
            System.out.println("Lambda this 的 class: " + this.getClass().getName());
            System.out.println("  外部类 prefix: " + this.prefix);  // 直接用 this
        };

        System.out.println("===== this 引用对比 =====");
        anonRunnable.run();
        System.out.println("---");
        lambdaRunnable.run();
    }

    // ========== 对比3:变量遮蔽 ==========
    private String field = "外部类字段";

    public void compareVariableShadowing() {
        // 匿名内部类可以有自己的字段,遮蔽外部类同名变量
        Runnable anon = new Runnable() {
            private String field = "匿名内部类字段";  // 遮蔽外部类的 field

            @Override
            public void run() {
                System.out.println("匿名内部类 field: " + this.field);             // "匿名内部类字段"
                System.out.println("匿名内部类外部 field: " + LambdaVsAnonDemo.this.field); // "外部类字段"
            }
        };

        // Lambda 不能声明自己的字段,不会形成遮蔽
        // private String field = "xxx";  // ❌ 编译错误
        Runnable lambda = () -> {
            System.out.println("Lambda field: " + this.field);  // 永远是"外部类字段"
        };

        System.out.println("===== 变量遮蔽对比 =====");
        anon.run();
        System.out.println("---");
        lambda.run();
    }

    // ========== 对比4:编译产物 ==========
    public void compareBytecode() {
        // 匿名内部类:生成 LambdaVsAnonDemo$1.class
        Comparator<String> anonComp = new Comparator<String>() {
            @Override
            public int compare(String a, String b) {
                return a.length() - b.length();
            }
        };

        // Lambda:不生成 .class 文件,使用 invokedynamic
        Comparator<String> lambdaComp = (a, b) -> a.length() - b.length();

        List<String> names = Arrays.asList("大翔", "白歌", "小崔");
        names.sort(anonComp);
        System.out.println("匿名内部类排序: " + names);

        names = Arrays.asList("大翔", "白歌", "小崔");
        names.sort(lambdaComp);
        System.out.println("Lambda 排序:     " + names);

        System.out.println();
        System.out.println("匿名内部类 class: " + anonComp.getClass().getName());
        System.out.println("Lambda class:     " + lambdaComp.getClass().getName());
    }

    // ========== 对比5:实例初始化块 ==========
    public void compareInitBlock() {
        // 匿名内部类可以使用实例初始化块(Lambda 不行)
        List<String> departments = new ArrayList<String>() {{
            add("技术部");
            add("市场部");
            add("人力资源部");
            add("财务部");
        }};  // 双括号初始化 —— 匿名内部类的实例初始化块

        System.out.println("===== 双括号初始化(匿名内部类特有) =====");
        System.out.println("部门列表: " + departments);
        System.out.println("实际类型: " + departments.getClass().getName());
        // 注意:departments 的类型不是 ArrayList,而是它的匿名子类!
    }

    public static void main(String[] args) {
        LambdaVsAnonDemo demo = new LambdaVsAnonDemo();

        demo.compareSyntax();
        System.out.println();

        demo.compareThisReference();
        System.out.println();

        demo.compareVariableShadowing();
        System.out.println();

        demo.compareBytecode();
        System.out.println();

        demo.compareInitBlock();
    }
}
运行输出:
===== 写法对比 =====
匿名内部类: [飞翔科技] HELLO WORLD
Lambda:     [飞翔科技] HELLO WORLD

===== this 引用对比 =====
匿名内部类 this 的 class: LambdaVsAnonDemo$1
  外部类 prefix: [飞翔科技]
---
Lambda this 的 class: LambdaVsAnonDemo
  外部类 prefix: [飞翔科技]

===== 变量遮蔽对比 =====
匿名内部类 field: 匿名内部类字段
匿名内部类外部 field: 外部类字段
---
Lambda field: 外部类字段

匿名内部类排序: [小崔, 大翔, 白歌]
Lambda 排序:     [小崔, 大翔, 白歌]

匿名内部类 class: LambdaVsAnonDemo$4
Lambda class:     LambdaVsAnonDemo$$Lambda$1/...

===== 双括号初始化(匿名内部类特有) =====
部门列表: [技术部, 市场部, 人力资源部, 财务部]
实际类型: LambdaVsAnonDemo$5

易错场景

反例一:匿名内部类与 Lambda 混用导致 this 污染

// ❌ 错误:匿名内部类中嵌套 Lambda,this 容易混乱
public class Outer {
    private String name = "Outer";

    public Runnable createTask() {
        Runnable r = new Runnable() {
            private String name = "Anonymous";

            @Override
            public void run() {
                // 在匿名内部类中使用 Lambda
                Thread t = new Thread(() -> {
                    System.out.println(this.name);  // this 指向谁?
                    // 答案:匿名内部类实例!
                    // Lambda 的 this 是定义它的外部范围 —— 这里就是匿名内部类
                });
                t.start();
            }
        };
        return r;
    }
}
// 输出: "Anonymous"(而非 "Outer"),容易造成困惑

纠正:在匿名内部类中需要引用外部外部类时,使用 Outer.this:

Thread t = new Thread(() -> {
    System.out.println(Outer.this.name);  // 明确引用最外层的 Outer
});

反例二:双括号初始化的隐患

// ⚠️ 看似方便,但有隐患
List<String> list = new ArrayList<String>() {{
    add("技术部");
    add("市场部");
}};

// 隐患1:创建了 ArrayList 的匿名子类,不是纯粹的 ArrayList
list.getClass().getName();  // "Main$1"

// 隐患2:如果序列化,匿名内部类不可序列化(除非外部类也实现 Serializable)
// 隐患3:持有外部类引用 this$0,可能导致内存泄漏

纠正:JDK 8 优先使用 Arrays.asList() 或 Stream:

// ✅ 更好的方式
List<String> list = Arrays.asList("技术部", "市场部");
// 或
List<String> list = new ArrayList<>(Arrays.asList("技术部", "市场部"));

反例三:匿名内部类中修改非 effectively final 变量

// ❌ 错误:想在匿名内部类中修改外部变量
int count = 0;
Runnable r = new Runnable() {
    @Override
    public void run() {
        count++;  // ❌ 编译错误:count 不是 effectively final
    }
};
count++;  // 这也会导致上面的编译错误

纠正:

// ✅ 使用 AtomicInteger
AtomicInteger count = new AtomicInteger(0);  // 引用不变,内容可变
Runnable r = new Runnable() {
    @Override
    public void run() {
        count.incrementAndGet();  // ✅ 可以修改内容
    }
};

// ✅ 使用数组
int[] count = {0};  // 引用不变
Runnable r = new Runnable() {
    @Override
    public void run() {
        count[0]++;  // ✅ 可以修改元素
    }
};

面试考点

Q1:匿名内部类和 Lambda 表达式的本质区别是什么?

① 字节码层面:匿名内部类生成独立的 .class 文件(Outer$1.class),Lambda 使用 invokedynamic 指令在运行时动态生成方法句柄,不产生 .class 文件; ② this 引用:匿名内部类的 this 指向自身实例,Lambda 的 this 指向定义它的外部类实例; ③ 作用域:匿名内部类有独立作用域,可以声明自己的字段和方法,Lambda 使用词法作用域,不能声明新变量; ④ 适用场景:Lambda 只能用于函数式接口(只有一个抽象方法的接口),匿名内部类可以用于任意接口或抽象类。

Q2:为什么匿名内部类不能定义构造方法?

因为构造方法名必须与类名相同,而匿名内部类没有类名。但可以通过以下方式实现类初始化逻辑: ① 实例初始化块({ } 代码块),编译后会被合并到构造方法中; ② 调用父类的带参构造方法:new ParentClass(arg) { }。

Q3:匿名内部类的双括号初始化 new ArrayList(){{add(...);}} 有什么风险?

① 创建了匿名子类,类型不是 ArrayList 本身,序列化、反射等场景下可能出问题; ② 持有外部类引用 this$0,可能导致外部类无法被 GC; ③ 破坏了 equals() 的对称性(匿名子类与 ArrayList 的 equals 可能不对称); ④ 如果匿名子类中使用了外部类的实例字段,还可能引发序列化问题。

Q4:匿名内部类可以实现多个接口吗?

不可以。匿名内部类的语法是 new 类名/接口名() { },只能指定一个类型。这是语法限制。如果需要实现多个接口,应使用局部内部类或单独的命名类。这是一个经典的面试陷阱——很多人回答"可以",但混淆了"可以继承一个类并实现接口"(这是局部内部类的特性)。

Q5:JDK 8 中 Lambda 是否完全能替代匿名内部类?

不能完全替代。Lambda 只能用于函数式接口(只有一个抽象方法的接口)。以下场景仍需匿名内部类: ① 需要实现多个方法(非函数式接口); ② 需要继承抽象类或具体类; ③ 需要在内部声明自己的字段或方法; ④ 需要实例初始化块; ⑤ 需要通过 this 访问自身实例。 此外,Lambda 不能访问非 effectively final 的变量(和匿名内部类一样),但 Lambda 还不支持自身递归。

上一页
静态内部类