一文带你真正理解Java中的内部类
作者:JAVA旭阳 发布时间:2023-11-24 20:42:07
概述
不知道大家在平时的开发过程中或者源码里是否留意过内部类,那有思考过为什么要有内部类,内部类都有哪几种形式,静态内部类和普通内部类有什么区别呢?本篇文章主要带领大家理解下这块内容。
内部类介绍和分类
顾名思义,内部类是指一个类在另外一个类的内部,是定义在另一个类中的类。根据类的位置和属性不同,可以分为下面几种。
常规内部类
@Data
public class Tree {
private String treeName;
private String treeType;
private List<Leaf> leafs;
@Data
public class Leaf {
private String color;
private String leafSize;
public void show() {
System.out.println("tree name: " + Tree.this.treeName);
System.out.println("tree name: " + treeName);
}
}
public static void main(String[] args) {
Tree tree = new Tree();
Leaf leaf = tree.new Leaf();
}
}
上面就是一个内部类的例子,Leaf是Tree的内部类。
内部类中可以直接访问外部类的数据,包括私有数据。
常规内部类中的方法或者字段不能是静态的。
内部类中可以使用如下的语法
Tree.this.treeName
。内部类创建对象需要外部对象的存在,如下:
Tree tree = new Tree();
Leaf leaf = tree.new Leaf();
字节码分析:
我们查看下内部类的字节码,如下图:
我们看到内部类Leaf的构造方法init,实际上会隐式地将外部对象传入,初始化,这样才能在内部类中访问。
局部内部类
局部内部类,比如只有在一个方法内部创建。
@Data
public class Tree {
private String treeName;
private String treeType;
private List<Leaf> leafs;
public void treeRoot(int height) {
class TreeRoot {
private int rootHeight;
public void showRootHeight() {
this.rootHeight = height;
System.out.println("root height " + height);
}
}
TreeRoot root = new TreeRoot();
root.showRootHeight();
}
}
局部类不能用public或private访问说明符进行声明,因为作用域只在这个局部,没有必要。
局部内部类可以完全将自己隐藏起来,体现良好的封装性。
局部内部类可以直接访问方法的变量。
匿名内部类
匿名内部类,就更加简洁了,连类名都省略了, 这个配合lambda食用,非常简便,想必大家也经常使用了。
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("runnable");
}
};
Runnable runnable2 = () -> System.out.println("runnable");
}
匿名内部类也体现了良好的封装性和简洁性。
静态内部类
最后,再介绍下静态内部类,这个也使用的非常频繁。java源码中也有很多这样的例子,比如HashMap中,Node节点就是一个静态内部类。
如果用static来修饰一个内部类,那么就是静态内部类。这个内部类属于外部类本身,但是不属于外部类的任何对象。因此使用static修饰的内部类称为静态内部类。静态内部类有如下规则:
静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。
外部类可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象访问其实例成员。
静态内部类和普通内部类的区别
我们可以通俗按下面的方式理解:
内部类:就是我是你的一部分,我了解你,我知道你的全部,没有你就没有我。(所以内部类对象是以外部类对象存在为前提的)
静态内部类:就是我跟你没关系,自己可以完全独立存在,但是我就借你的壳用一下,来隐藏自己。
从字节码角度上看,静态内部类和非静态内部类最大的区别是:非静态内部类编译后隐式保存着外部类的引用(就算外部类对象没用了也GC不掉),但是静态内部类没有。
内部类的作用
通过上面的了解,我想内部类还是有一定的意义的。
内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。
内部类可以对同一个包中的其他类隐藏起来。
其实内部类更多的时候,不想把这个类暴露出去,它可能只是外部类的一个逻辑组成部分,不需要其他地方知道什么,这时候我们用内部类更加的清楚。
来源:https://juejin.cn/post/7137699156973322247


猜你喜欢
- 本文实例讲述了Java编程实现基于TCP协议的Socket聊天室。分享给大家供大家参考,具体如下:这里使用Socket套接字进行编程,完成的
- 在Android中,线程内部或者线程之间进行信息交互时经常会使用消息,这些基础的东西如果我们熟悉其内部的原理,将会使我们容易、更好地架构系统
- 概述由于微信公众平台的特殊机制,所有的信息都由微信服务器转发而来,因此服务器是无法使用Session对用户会话的上下文进行管理的。为此Sen
- 一 引入考虑实现一种三轴机器人控件。三轴机器人用来将某种工件从一个位置运送到另一个位置。其X轴为手臂轴,可以正向和反向运动,它处于末端,直接
- 本文实例讲述了Android选项菜单用法。分享给大家供大家参考。具体如下:Android平台下所提供的菜单大体上可分为三类:选项菜单、上下文
- 在我们移动应用开发过程中,偶尔有可能会接到这种需求:1、在手机桌面创建一个窗口,类似于360的悬浮窗口,点击这个窗口可以响应(至于窗口拖动我
- 公司app要求做一个扭蛋功能,其实就是一个可拖动层叠卡片列表,原理还是由一个自定义Recyclerview和LayoutManager来实现
- 本文实例讲述了C#实现对字符串进行大小写切换的方法。分享给大家供大家参考。具体实现方法如下:C#代码如下:public class Prog
- 本文实例为大家分享了Unity实现攻击范围检测并绘制检测区域的具体代码,供大家参考,具体内容如下一、圆形检测using System.Col
- 下面通过代码看下JAVA查询树结构数据(省市区)使用hutool工具实现代码:@PostMapping("/getTree&quo
- package cn.mypic; import java.io.Buffe
- 前言最近数据库大作业要连接数据库,看了很多博客文章终于连接好了,但是没有看到一篇博客是能直接连接完成的,所以在这记录一下希望能帮助大家sql
- 引出泛型我们通过如下的示例,引出为什么泛型的概念。public class Test {public static void main(St
- 用注解实现Mybatis插入数据返回自增的主键Id我们在数据库表设计的时候,一般都会在表中设计一个自增的id作为表的主键。这个id也会关联到
- 大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中:<select
- 背景:有时候string类型的数据取出来是个很标准的key、value形式,通过Gson的可以直接转成map使用方式:Gson gson =
- Mybatis与Ibatis的区别: 1、Mybatis实现了接口绑定,使用更加方便 在ibatis2.x中我们需要在DAO的实现类中指定具
- 这篇文章主要介绍了spring boot 2整合swagger-ui过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的
- 一、需求背景有时候,我们需要在屏幕上显示新的信息,同时移除旧的信息,一般情况下我们通过VISIBILITY或者GONE来对需要显示或者隐藏的
- 需求分析:我们在做winform开发的时候,有时候需要让程序休眠几秒钟,但是如果我们直接使用 Thread.Sleep()函数的话,页面UI