什么

定义在一个类内部的类,称为内部类(累不累),如下:

public class A {
    private int c = 1;

    public class C {
        public void test() {
            System.out.println("c:" + c);
        }
    }
}

C称为A的内部类,简称内部类

A称为C的外部类,简称外部类

而且内部类能访问外部类的成员(静态成员、实例成员),当然有一些限制,限制如下

4种声明方式

按照内部类的声明方式,分为4种内部类:

  1. 静态内部类

    像类的静态成员一样声明的类,就称呼为“静态内部类”

    public class A {
        private static String b = "b";
            private int c = 1;
    
            // B是A的静态内部类
        public static class B {
            public void test() {
                System.out.println(b);
            }
        }
    }  

    静态内部类,只能访问外部类的静态成员(方法和变量),并且可以像类的成员一样使用修饰符(public/protected/private);

    创建静态内部类对象的方式:A.B b = new A.B();

  2. 成员内部类

    新类的实例成员(未加static修饰)声明的类,称为“成员内部类”

    public class A {
        private static String b = "b";
            private int c = 1;
    
            // C是A的成员内部类
        public class C {
            public void test() {
                System.out.println(c);
                            System.out.println(b);
            }
        }
    }

    成员内部类,访问外部类的一切(静态,还是实例),就像成员方法一样,并且可以像类的成员一样使用修饰符(public/protected/private)

    创建成员内部类对象的方式:

    A a = new A();
    A.C c = a.new C();
  3. 方法内部类

    在一个代码块声明的类称为方法内部类,代码块包括(方法内、静态代码块内、实例代码块内)

    public class A {
        private static String b;
        private int c;
    
            // 成员方法
        public void test() {
            final int d = 1;
            // 方法内部类
            class D {
                public void test() {
                    // 访问静态变量
                    System.out.println(b);
                    // 访问实例变量
                    System.out.println(c);
                    // 访问方法final类型的局部变量
                    System.out.println(d);
                }
            }
        }
    }

    方法内部类,和它所在的方法(代码块),具有相同的访问能力,如果上面代码是在static方法中声明的,那么内部类D不能访问c变量。

    jdk1.8 方法内部类,能够访问非final类型的局部变量,本质相当有在内部类D内保存了副本

  4. 匿名内部类

    匿名内部类也就是没有名字的内部类

    正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写

    但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口

内部类的本质

内部类的语法颇为奇怪,我们来看看如下代码,编译后的字节码文件!

public class A {
    private static String b = "b";
    private int c = 1;
        // 静态内部类
    public static class B {
        public void b() {
            System.out.println(b);
        }
    }
        // 成员内部类
    class C {
        public void c() {
            System.out.println(c);
        }
    }
}

  1. A.java文件被编译成了多个class文件
  2. A类对应A.class
  3. B类对应A$B.class
  4. C类对应A$C.class

内部类会被编译成单独的class文件,那意味JVM解释执行class文件时类“B”和类A是独立的,由此可以见内部类也是一种语法糖!

对于JVM来说,类A的private b和c 成员,怎么能分别被类B和类C访问到的了!

用javap命令反编译类A.class来看看:

秘密就来自,编译器为外部类生的两个静态访问方法,Stinrg access$000()返回b变量的值,int access$100(A a)返回a对象的c成员变量值;

而在静态内部类B中,编译器将访问静态变量b的地方替换为如上方法:

// 静态内部类
public static class A$B {
    public void b() {
        System.out.println(A.access$000());
    }
}

在成员内部类C中,原理也是如此,不过增加了更多的东西,反编译A$C.class:

  1. 新增了成员字段final A $this;
  2. 构造方法添加形参 `A$C(A obj);
  3. 访问外部类成员变量的地方会被替换成:System.out.println(A.access$100($this));

你一定会好奇成员构造方法中的外部类对象的参数从哪里传入的!看看我们是怎么声明内部类的对象的

A a = new A();
A.C c = a.new C();

将会被编译器替换成:

A a = new A();
A$C c = new A$C(a);

内部类的使用时机

两个类之间紧密联系时,可以使用内部类:

  1. 当一个类需要访问另外一个类的许多属性时,内部类可以简化访问代码
  2. 实现更好封装性,比如:B 类仅仅被A类访问时,可以将B类作为A的私有内部类
  3. 使代码更简洁,匿名内部类

Java 内部类详解的更多相关文章

  1. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  2. [转] Java内部类详解

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

  3. 【转】Java内部类详解

    一.内部类基础 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.广泛意义上的内部类一般来说包括这四种:成员内部类.局部内部类.匿名内部类和静态内部类.下面就先来了解一 ...

  4. Java内部类详解(一)

    (转自:http://blog.csdn.net/wangpeng047/article/details/12344593) 很多人对于Java内部类(Inner Class)都十分陌生,甚至听都没听 ...

  5. Java内部类详解 2

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  6. 【Java_基础】Java内部类详解

    1.四种内部类 java中的四种内部类:成员内部类.静态内部类.局部内部类和匿名内部类.其中匿名内部类用到的最多. 1.1.成员内部类 若一个类定义在另一个类的内部作为实例成员,我们把这个作为实例成员 ...

  7. Java内部类详解(转)

    说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就来一探究竟.下面是本 ...

  8. (转)java内部类详解

    本文转自http://www.cnblogs.com/dolphin0520/p/3811445.html,谢谢作者 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能 ...

  9. Java——内部类详解

    说起内部类,大家肯定感觉熟悉又陌生,因为一定在很多框架源码中有看到别人使用过,但又感觉自己使用的比较少,今天我就带你具体来看看内部类. 内部类基础 所谓内部类就是在类的内部继续定义其他内部结构类. 在 ...

随机推荐

  1. Java Spring MVC项目搭建(一)——Spring MVC框架集成

    1.Java JDK及Tomcat安装 我这里安装的是JDK 1.8 及 Tomcat 8,安装步骤详见:http://www.cnblogs.com/eczhou/p/6285248.html 2. ...

  2. Xcode7中 添加 .dylib

    转一个 Xcode 7 缺少 *.dylib库的解决方法 Xcode7中 Link Binary With Libraries 没有 .dylib库,只能找到对应的 .tbd,但不能代替使用,通过查找 ...

  3. UVa 10034 - Freckles

    题目大意:给出n个点的坐标(x,y),要求用线段将n个点连接起来,求最小的线段和. 最小生成树问题,用Kruskal算法进行求解,其中用到了并查集.将所有的点连接,构成一张图,对每一条边进行编号,两点 ...

  4. 【angularjs】【学习心得】路由基础篇

    原文:http://www.imooc.com/wenda/detail/236998 AngularJS自带有路由模块ngRoute,但是有经验的老师都推荐我们使用功能更完善更强大的ui-route ...

  5. 解决xtrabackup command not found no mysqld group 问题

    现象:手动执行xtrabackup没问题,环境变量检查过也没问题.放到执行计划中 会报错: sh: xtrabackup_56: command not found innobackupex: Err ...

  6. Prolog 外部不能有 DOCTYPE 声明。处理资源 'http://192.168.115.152:8082/api/EmpApi.aspx' 时出错。第 3 行,位置: 11

    在Default.aspx代码中删除以下代码(其他窗口也是这样删除): <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitiona ...

  7. hadoop在windows下安装运行

    1.下载windows环境下编译的hadoop-2.7.2.x64win.zip 2.解压至D:\BigData\hadoop-2.7.2 3.修改D:\BigData\hadoop-2.7.2\et ...

  8. 基于Ubuntu 14.04构建mysql5.6 Docker镜像

    我们的目的是创建一个基于Ubuntu 14.04 的MySQL的 Docker Image,并且在新创建出来的容器里自动启动MySQL服务接受外部连接 步骤: 1. 首先创建一个目录并在目录下创建一个 ...

  9. css3基础知识——回顾

    1.属性选择器 完全匹配的属性选择器 [id=article]{} 示例: <style> input[type=text]{ border: 2px solid red;} </s ...

  10. 深度理解微信小程序的思想

    这篇文章不涉及小程序技术方面得问题,只讨论小程序的核心问题. 探讨一个问题最好的方法是问"为什么",这篇文章主要思路是通过回答以下几个问题来探讨微信小程序的"思想&quo ...