浅谈Java匿名内部类

发布时间:2026/6/28 5:37:41
浅谈Java匿名内部类 一、特点基本定义匿名内部类没有类名的局部内部类只能在定义时直接创建唯一对象只能使用一次。核心特点1. 没有类名不能手动实例化第二次没有类名无法用new 类名()再次创建对象只能在定义的同时new出来仅能使用一次newRunnable(){Overridepublicvoidrun(){}}.run();2. 必须继承一个父类 或 实现一个接口语法格式二选一实现接口new接口名(){重写抽象方法}继承普通类/抽象类new父类名(){重写方法}匿名内部类本质隐式继承/实现编译器自动生成外部类$数字.class字节码文件。3. 访问权限相关可以访问外部类所有成员私有、静态、实例都可以方法内的局部变量被匿名内部类使用时Java 8局部变量隐式 final不能二次赋值Java 7及以前必须手动加final不能定义静态成员静态变量、静态方法只能有实例成员4. 作用域局限属于局部内部类只能定义在方法、代码块、参数位置出了当前方法作用域就无法使用外部不能访问该匿名类5. 只能重写需要的方法不能新增对外调用的方法如果在匿名类里新增自定义方法外部无法调用只能在类内部自己用只能调用父类/接口中声明的方法6. 不能有构造方法因为没有类名无法定义构造器可以用实例代码块做初始化操作。7. 字节码文件编译后生成独立字节码外部类$1.class、外部类$2.class数字代表第几个匿名内部类。优缺点优点代码简洁不用单独新建类文件快速实现接口/重写父类方法适合一次性使用场景缺点只能使用一次无法复用结构可读性差复杂逻辑不建议使用不能定义静态成员、不能写构造方法补充Lambda 与匿名内部类区别函数式接口优先用 LambdaLambda 本质不是匿名内部类只是语法糖不会生成额外 class 文件匿名内部类会生成独立字节码。二、匿名内部类 vs 局部内部类 核心区别基础定义局部内部类定义在方法/代码块中、有类名的内部类属于局部范围。匿名内部类定义在方法中、没有类名的局部内部类属于局部内部类的特殊形式。详细区别对比1. 类名局部内部类有类名可以多次创建对象voidtest(){classA{}Aa1newA();Aa2newA();// 多次实例化}匿名内部类没有类名只能在定义时创建唯一一次对象无法重复 new2. 构造方法局部内部类可以正常定义构造方法、重载构造器匿名内部类没有类名不能写构造方法只能用实例代码块初始化3. 能否定义多个方法、新增方法局部内部类可以随意新增成员方法创建对象后能调用所有方法匿名内部类新增的方法外部无法调用只能调用父类/接口中已声明的方法4. 能否定义静态成员局部内部类不能定义静态变量、静态方法和匿名内部类一致匿名内部类同样不能定义静态成员5.字节码文件局部内部类外部类$局部类名.class匿名内部类外部类$1.class、外部类$2.class用数字命名6. 使用方式局部内部类先定义类 → 再new 类名()创建对象可多次使用匿名内部类定义实例化必须一步完成只能用一次7. 继承/实现数量局部内部类可以实现多个接口、继承一个类使用方式和普通类一致匿名内部类只能要么继承一个类要么实现一个接口不能同时既继承又实现多个接口8. 作用域共同点两者都属于局部只能在当前方法/代码块内使用外部访问不到都可以访问外部类所有成员使用方法内局部变量时变量必须隐式final不能二次赋值表格精简总结对比项局部内部类匿名内部类类名有无实例化可多次new只能一次构造方法可以定义不能定义新增方法外部可调用外部不可调用字节码命名带类名数字编号适用场景需要多次复用、逻辑复杂一次性回调、传参简写简单记忆有名字、能多次创建 →局部内部类没名字、只能用一次、写完立刻new →匿名内部类三、匿名内部类实际开发常用场景事件监听Swing/Android 经典场景GUI 界面按钮点击、输入框监听不需要专门写一个监听类直接用匿名内部类实现监听接口。button.addActionListener(newActionListener(){OverridepublicvoidactionPerformed(ActionEvente){System.out.println(按钮被点击了);}});优点一次性监听用完即弃不用新建类文件。多线程开发实现 Runnable 接口快速创建线程不用单独写一个线程类。// 方式1直接传参newThread(newRunnable(){Overridepublicvoidrun(){System.out.println(子线程执行任务);}}).start();Java8 后一般用 Lambda 简化但底层原理源自匿名内部类。集合排序Collections.sort 自定义比较器 Comparator对 List 集合自定义排序规则临时写排序逻辑。ListIntegerlistArrays.asList(3,1,2);Collections.sort(list,newComparatorInteger(){Overridepublicintcompare(Integero1,Integero2){// 降序排序returno2-o1;}});方法参数需要接口/抽象类对象临时实现很多框架方法参数是接口类型不想新建实现类直接匿名内部类传入。比如回调、策略模式临时策略、文件过滤器FileFilter// 只筛选 .txt 文件File[]filesnewFile(D:/).listFiles(newFileFilter(){Overridepublicbooleanaccept(Filepathname){returnpathname.getName().endsWith(.txt);}});临时重写父类方法不想新建子类需要临时重写普通类/抽象类的某个方法只使用一次// 重写toString临时自定义ObjectobjnewObject(){OverridepublicStringtoString(){return临时重写的对象;}};回调函数场景早期框架常用异步操作完成后执行回调逻辑比如网络请求、数据库操作成功/失败回调早期没有 Lambda 时全部用匿名内部类实现。单元测试快速构建接口实现类测试某个依赖接口的方法临时写实现类传入方便测试各种分支场景。补充为什么现在很多场景用 Lambda 替代匿名内部类可以实现多个抽象方法的接口Lambda 只能用于函数式接口只有一个抽象方法。只要接口是函数式接口优先 Lambda如果接口有多个抽象方法、需要重写多个方法只能用匿名内部类不能用 Lambda。