Java中的四种内部类

我发现最近真是越来越没有东西写了。。。不可能天天学习新知识啊,最近在复习阶段了,复习的东西大多数是博客里写过的/(ㄒoㄒ)/

复习Java基础的时候认真看了一下Java的内部类,这东西之前了解过,但是没有写过代码实验一下,今天就来手写代码夯实夯实基础。也懒得写那么多文字了,博客精简一点剩下时间用来复习。

Java中的内部类分为:
+ 普通内部类:也叫成员内部类
+ 局部内部类
+ 静态内部类
+ 匿名内部类

普通内部类

普通内部类就是直接写在宿主类中的(我这篇文章中称为宿主类,和外部类区分开),并且不带static,如下:

public class TestInnerClass {
    private String outerName = "outer";

    //普通内部类
    public class InnerClass1{
        // 普通内部类可以访问宿主类的一切属性
        public String name = outerName+": "+"InnerClass1";
    }

    @Test
    public void testNormal(){
        // 创建一个普通内部类对象
        InnerClass1 innerClass1 = new InnerClass1();
        // 宿主类可以访问其属性
        System.out.println(innerClass1.name);
    }
}

为什么普通内部类可以带public这种访问修饰符呢?外部类可以创建一个它的实例对象吗?

验证如下:

public class TestInnerClass2 {
    @Test
    public void test(){
        // 首先创建一个宿主类的对象
        TestInnerClass t = new TestInnerClass();
        // 通过宿主类的对象new出一个内部类的对象
        TestInnerClass.InnerClass1 innerClass1 = t.new InnerClass1();
        // 可以获取内部类public的属性
        System.out.println(innerClass1.name);
    }
}

普通内部类是依存于宿主类的实例对象存在的,通过宿主类的实例对象才能new出一个内部类的实例,不得不说,这个语法还蛮少见的。

当然,如果普通内部类声明为private的,外部类就不可以访问了。

局部内部类

局部内部类是宿主类的一个方法中的,比较特殊:

public class TestInnerClass3 {
    @Test
    public void test(){
        String methodName = "test";
        // 局部内部类,生效范围为方法内部作用域
        class InnerClass3{
            // 可以获取方法中声明的局部变量
            public String className = methodName+": InnerClass3";
        }
        // 在方法中可以使用
        InnerClass3 innerClass3 = new InnerClass3();
        System.out.println(innerClass3.className);
    }
}

但是局部内部类有一个特点是不能加上访问权限限定符,例如public、private:

public class TestInnerClass3 {
    @Test
    public void test(){
        String methodName = "test";
        // 报错!!!
        public class InnerClass3{
            public String className = methodName+": InnerClass3";
        }
        InnerClass3 innerClass3 = new InnerClass3();
        System.out.println(innerClass3.className);
    }
}

但是可以加上abstract、final这样的修饰符。

静态内部类

静态内部类和普通的类最为相似,唯一的区别可以看作就是要通过一个类来获取。这种内部类平时也是用的比较多的,所以这里也不特别说明。

public class TestInnerClass4 {
    private static String className = "TestInnerClass4";
    public static class InnerClass4{
        // 只能获取宿主类的静态字段
        private String name = className+": InnerClass4";
    }
}

匿名内部类

匿名内部类平时也用的特别多,常见的例子就是new一个Thread:

public class TestInnerClass5 {
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                System.out.println("线程启动");
            }
        }.start();
    }
}

这里实际上是创建了一个Thread的子类,并重写了run方法。

会不会生成单独的class文件

经过测试,所有内部类都会产生单独的class文件,并且命名是:

  • 普通内部类和静态内部类都是:(宿主类名)$(内部类名)
  • 局部内部类是:(宿主类名)$(编号)(内部类名)
  • 匿名内部类是:(宿主类名)$(编号)

普通内部类能访问宿主类实例字段的原理

  1. 编译器自动为内部类添加一个成员变量,该成员变量的类型和外部类的类型相同,这个成员变量就是指向外部类对象引用。
  2. 编译器自动为内部类的构造方法添加一个参数,参数的类型是外部类的类型,在构造方法内部使用这个参数为1中添加的成员变量赋值。
  3. 在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/java%e4%b8%ad%e7%9a%84%e5%9b%9b%e7%a7%8d%e5%86%85%e9%83%a8%e7%b1%bb/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年5月23日
下一篇 2020年5月24日

相关推荐

  • 深入理解java虚拟机第三版读书笔记09

    续深入理解java虚拟机第三版读书笔记08 类加载器 通过一个类的全限定名来获取描述该类的二进制字节流称为类加载器。类加载器可以用户自定义,是java语言流行的一项原因 类与类加载…

    2020年1月23日
    0130
  • 网络编程之AIO

    AIO介绍 AIO是JDK1.7引入的,也称为NIO 2.0 NIO的同步非阻塞类似于轮询,让Selector去询问各个通道的状态。 而AIO则是通过Future实现真正的异步,让…

    Java 2020年2月8日
    0280
  • Java日志框架JUL和Log4j介绍

    日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用。 日志实现:JUL、logback、log4j、l…

    2020年2月14日
    0310
  • IEEE754浮点数标准和舍入规则

    整理一下之前的笔记 浮点数与定点数 定点数 小数点在计算机中通常有两种表示方法,一种是约定所有数值数据的小数点隐含在某一个固定位置上,称为定点表示法,简称定点数。 其实整数也算是一…

    2020年4月2日
    01.2K0
  • 线程内部的run方法可以向外抛出异常吗?

    提出问题 线程的run方法向外可以抛出异常吗,或者能被主线程捕获异常吗?比如下面这段代码: public static void main(String[] args) { try…

    Java 2020年5月20日
    06500
  • HashMap源码分析

    HashMap是java中非常常见的一个数据结构,在这篇文章里,我依然以Map中的操作为导向来循序渐进研究HashMap中的源码,阅读这篇文章需要的前置知识有: 弱平衡的二叉查找树…

    Java 2020年2月12日
    0220
  • 常用开源数据库连接池C3P0、Druid介绍

    概述 很多时候,连接的混乱管理所造成的系统资源开销过大成为制约大型企业级应用效率的瓶颈。因为每一次WEB请求都要建立一次数据库连接,建立连接是一个耗费资源的活动,每次都得花费0.0…

  • JDK8-Stream流库详解

    流提供了一种让我们可以在比集合更高的概念级别上指定计算的数据视图。通过使用流,我们可以说明想要完成什么任务,而不是说明如何去实现它。 流的创建 Collection.stream(…

    Java 2020年2月11日
    0150
  • 深入理解java虚拟机第三版读书笔记10

    以下是第十章 前端编译与优化的内容 Java中的编译可能是指: 前端编译:把*.java文件转变成*.class文件的过程 即时编译(JIT):运行期把字节码转变成…

    Java 2020年1月25日
    0130
  • 深入理解java虚拟机第三版读书笔记07

    附: Java虚拟机规范-Java虚拟机指令集:JDK8 Java虚拟机规范-Java虚拟机指令集:JDK13 续深入理解java虚拟机第三版读书笔记06 字节码指令简介 Java…

    Java 2020年1月21日
    0230

发表回复

登录后才能评论