当前位置: 首页 > news >正文

Java常见错误-内部类-简要分析

Java常见错误-内部类-简要分析

  • 概念
  • 分类
    • 成员内部类(非静态内部类)
    • 静态内部类
      • 成员内部类和静态内部类区别
    • 局部内部类
    • 匿名内部类
  • 注意事项
  • 总结

概念

内部类,顾名思义,就是在一个类的内部定义的类。这种设计允许将一个类的实现细节封装起来,并可以实现非常紧密的耦合,对于某些特定场景下,比如事件监听器模型、线程创建等,内部类能提供更加优雅和简洁的解决方案

分类

  1. 成员内部类(非静态内部类):这是最普通的内部类形式,它作为外部类的一个成员存在,可以直接访问外部类的成员变量和方法,即使它们是私有的。

  2. 静态内部类(静态嵌套类):静态内部类与成员内部类的主要区别在于静态内部类不需要依赖于外部类的实例,它可以通过外部类直接访问,类似于外部类中的静态成员。

  3. 局部内部类:局部内部类是在方法或代码块中定义的类,它的作用域仅限于该方法或代码块。它可以访问外部类的成员,同时也可以访问所在方法的局部变量,但要求这些局部变量必须被声明为final。

  4. 匿名内部类:没有名字的内部类,通常用来创建某个接口的实例或者实现抽象类的一个子类。它可以直接在需要使用的地方创建并实例化,常用于事件处理、线程创建等场景。

成员内部类(非静态内部类)

public class memberOuterClass {private int data = 5;class InnerClass {void display() {System.out.println("Data from outer class: " + data);}}public static void main(String[] args) {OuterClass outer = new OuterClass();OuterClass.InnerClass inner = outer.new InnerClass();inner.display();}
}

反编译.class:

public class memberOuterClass {private int data = 5;public memberOuterClass() {}public static void main(String[] var0) {memberOuterClass var1 = new memberOuterClass();InnerClass var2 = var1.new InnerClass();var2.display();}class InnerClass {InnerClass() {}void display() {System.out.println("Data from outer class: " + memberOuterClass.this.data);}}
}

​ 可以发现反编译后的代码中,外部类和内部类都多了一个无参的构造方法无论外部类还是内部类,编译器自动添加默认无参构造函数是为了确保类的可实例化性、支持继承机制以及维护类实例与其环境的正确关联

静态内部类

  • 静态内部类内允许有static属性、方法;
public class OuterClass {private static int staticData = 10;static class StaticInnerClass {void display() {System.out.println("Static data from outer class: " + staticData);}}public static void main(String[] args) {OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();inner.display();}
}

成员内部类和静态内部类区别

1、在是否可以使用static修饰上

  • 成员内部类内不允许有static属性、static方法;除非final static存常量池中

2、对外部类的引用及互相访问上

  • 非静态成员内部类:可以直接访问外部类的所有成员(包括静态和非静态),因为它持有一个隐式的外部类实例的引用(通常称为this$0)。这意味着非静态内部类的实例化必须在外部类的实例上下文中进行
  • ``静态成员内部类`不持有对外部类实例的直接引用,因此它不能直接访问外部类的非静态成员变量和方法 。它可以访问外部类的静态成员(包括静态字段和方法),因为静态成员属于类本身,不依赖于类的实例进行创建

3、内部类创建上

  • 静态内部类
public class Outer {public static class StaticInner {public void show() {System.out.println("静态内部类");}}
}// 使用静态内部类,无需创建Outer实例
Outer.StaticInner inner = new Outer.StaticInner();
inner.show();
  • 成员内部类
public class Outer {public class MemberInner {public void show() {System.out.println("成员内部类");}}
}// 使用成员内部类,需先创建Outer实例
Outer outer = new Outer();
Outer.MemberInner inner = outer.new MemberInner();
inner.show();

小结静态内部类的实例化不需要外部类的实例。成员内部类的实例化需要先有外部类的实例,并通过外部类实例来创建内部类实例

4、一个外部类内多个成员内部类分别继承不同父类,实现"多继承"

public class Outer {// 第一个内部类继承自类Apublic class InnerA extends A {// InnerA 的实现}// 第二个内部类继承自类Bpublic class InnerB extends B {// InnerB 的实现}public static void main(String[] args) {// 创建 InnerA 和 InnerB 的实例InnerA innerA = new Outer().new InnerA();InnerB innerB = new Outer().new InnerB();}
}

局部内部类

public class OuterClass {void someMethod() {final int localData = 7;class LocalInnerClass {void show() {System.out.println("Local data: " + localData);}}LocalInnerClass local = new LocalInnerClass();local.show();}public static void main(String[] args) {OuterClass outer = new OuterClass();outer.someMethod();}
}

注:局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

匿名内部类

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("Hello");list.add("World");list.forEach(new java.util.function.Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});// 或者使用Lambda表达式简化(也是匿名内部类的一种体现)list.forEach(s -> System.out.println(s));}
}

匿名内部类是一种特殊的类,它不具备明确的构造器,这限制了它的应用场景。主要用途是作为接口的简短实现,尤其是用作回调机制。在编译时,它会被系统自动生成一个类似于Outer$1.class的名称。通常,匿名内部类用于扩展已有类或实现接口,并专注于提供必要的方法实现,而不涉及额外的功能

注意事项

//TODO

总结

​ 内部类是Java语言提供的一种特殊类,它允许类定义嵌套在其他类中,这为程序设计提供了更大的灵活性。不同类型的内部类有着不同的应用场景和访问规则,如成员内部类用于需要访问外部类非静态成员的情况,静态内部类更像一个独立的类但逻辑上属于外部类,局部内部类和匿名内部类则常用于临时性需求,如事件处理或实现特定接口的简短实现。理解并恰当使用内部类,可以使代码更加清晰、高效和易于维护。

相关文章:

  • 贰[2],VisionMaster/.NetCore的WPF应用程序调用控件
  • 佛教祭拜小程序-寺庙小程序-纪念馆小程序
  • 【Python】pip 使用方法详解
  • Execl数据导入 EasyExcel实现
  • PICRUSt2在微生物功能预测分析中的应用解读
  • 【区分vue2和vue3下的element UI TimePicker 时间选择器组件,分别详细介绍属性,事件,方法如何使用,并举例】
  • Qt+qss动态属性改变控件状态切换的样式
  • Flutter打包网络问题解决办法
  • 【Go语言精进之路】构建高效Go程序:了解切片实现原理并高效使用
  • 《编译原理》期末考试复习手写笔记(二)+真题(第四、五、六章)+课后习题答案
  • Flutter中同步与异步
  • 10倍速开发开关电源:PSIM DLL集成指南与如何单步调试你的代码
  • 【面试干货】如何选择MySQL数据库存储引擎(MyISAM 或 InnoDB)
  • 使用 Python 的 Tkinter 来创建 GUI 应用程序
  • 【排序算法】总结篇
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • Angular 响应式表单之下拉框
  • CentOS7 安装JDK
  • java2019面试题北京
  • js操作时间(持续更新)
  • Js基础知识(一) - 变量
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • Map集合、散列表、红黑树介绍
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • Odoo domain写法及运用
  • Python十分钟制作属于你自己的个性logo
  • Spring Cloud Feign的两种使用姿势
  • Spring核心 Bean的高级装配
  • vue 配置sass、scss全局变量
  • Wamp集成环境 添加PHP的新版本
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 动态规划入门(以爬楼梯为例)
  • 给新手的新浪微博 SDK 集成教程【一】
  • 技术:超级实用的电脑小技巧
  • 前言-如何学习区块链
  • -- 数据结构 顺序表 --Java
  • 一些关于Rust在2019年的思考
  • mysql面试题分组并合并列
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • # 消息中间件 RocketMQ 高级功能和源码分析(七)
  • #includecmath
  • $jQuery 重写Alert样式方法
  • (1)(1.11) SiK Radio v2(一)
  • (1)Android开发优化---------UI优化
  • (39)STM32——FLASH闪存
  • (C++20) consteval立即函数
  • (LeetCode C++)盛最多水的容器
  • (二)JAVA使用POI操作excel
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试