Java 内部类详解
什么
定义在一个类内部的类,称为内部类(累不累),如下:
public class A {
private int c = 1;
public class C {
public void test() {
System.out.println("c:" + c);
}
}
}
C称为A的内部类,简称内部类
A称为C的外部类,简称外部类
而且内部类能访问外部类的成员(静态成员、实例成员),当然有一些限制,限制如下
4种声明方式
按照内部类的声明方式,分为4种内部类:
静态内部类
像类的静态成员一样声明的类,就称呼为“静态内部类”
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()
;成员内部类
新类的实例成员(未加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();
方法内部类
在一个代码块声明的类称为方法内部类,代码块包括(方法内、静态代码块内、实例代码块内)
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内保存了副本
匿名内部类
匿名内部类也就是没有名字的内部类
正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
内部类的本质
内部类的语法颇为奇怪,我们来看看如下代码,编译后的字节码文件!
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);
}
}
}
- A.java文件被编译成了多个class文件
- A类对应A.class
- B类对应A$B.class
- 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:
- 新增了成员字段
final A $this
; - 构造方法添加形参 `A$C(A obj);
- 访问外部类成员变量的地方会被替换成:
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);
内部类的使用时机
两个类之间紧密联系时,可以使用内部类:
- 当一个类需要访问另外一个类的许多属性时,内部类可以简化访问代码
- 实现更好封装性,比如:B 类仅仅被A类访问时,可以将B类作为A的私有内部类
- 使代码更简洁,匿名内部类
Java 内部类详解的更多相关文章
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
- [转] Java内部类详解
作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...
- 【转】Java内部类详解
一.内部类基础 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.广泛意义上的内部类一般来说包括这四种:成员内部类.局部内部类.匿名内部类和静态内部类.下面就先来了解一 ...
- Java内部类详解(一)
(转自:http://blog.csdn.net/wangpeng047/article/details/12344593) 很多人对于Java内部类(Inner Class)都十分陌生,甚至听都没听 ...
- Java内部类详解 2
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
- 【Java_基础】Java内部类详解
1.四种内部类 java中的四种内部类:成员内部类.静态内部类.局部内部类和匿名内部类.其中匿名内部类用到的最多. 1.1.成员内部类 若一个类定义在另一个类的内部作为实例成员,我们把这个作为实例成员 ...
- Java内部类详解(转)
说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就来一探究竟.下面是本 ...
- (转)java内部类详解
本文转自http://www.cnblogs.com/dolphin0520/p/3811445.html,谢谢作者 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能 ...
- Java——内部类详解
说起内部类,大家肯定感觉熟悉又陌生,因为一定在很多框架源码中有看到别人使用过,但又感觉自己使用的比较少,今天我就带你具体来看看内部类. 内部类基础 所谓内部类就是在类的内部继续定义其他内部结构类. 在 ...
随机推荐
- 利用cocoapods创建基于git的私有库
上一篇文章记录了我利用cocoapods创建基于SVN的私有库的全部过程,今天我再记录一下基于git创建的过程. 整体先说明一下创建一个私有的podspec包括如下那么几个步骤: 创建并设置一个私有的 ...
- session锁问题
碰到个问题,在使用了session时(如用户登录),如果当前请求时间过长,再执行其他请求都不会有响应,查找了网上资料发现,这个是session锁的问题 目前我们的程序基本流程如下: (1)加载Sess ...
- js架构设计模式——理解javascript中的MVVM开发模式
理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...
- 第五组UI组件:ProgressBar及其子类
ProgressBar组件也是一组重要的组件,ProgressBar本身代表了进度条组件,它还派生了两个常用的组件:SeekBar和RatingBar.ProgressBar及其子类在用上十分相似,只 ...
- javascript实现页面滚屏效果
当我们浏览网页的时候,时常会碰到可以滚动屏幕的炫酷网页,今天笔者对这一技术进行简单实现,效果不及读者理想中那般炫酷,主要针对滚屏的技术原理和思想进行分享和分析.本示例在页面右侧有五个数字标签,代表五个 ...
- 本地ssh连接到vbox中的linux
本机是window xp系统, 安装vbox,在vbox下安装linux,想在xp中用ssh连接linux,此时需要配置网络. 1.设置vbox的网络,选择host-only 2.设置window虚拟 ...
- TCP协议滑动窗口(一)——控制数据传输速率
窗口大小:TCP头中一个16位的域,表示当前可用接受缓冲区大小.在每个TCP对等段连接初始化时,告诉对方自己的窗口大小(不一定是满额,假如满额65201字节,可能暂时通告5840字节).若客户端接受数 ...
- 从php到浏览器的缓存机制,不得不看!
所有的php程序员都知道在php脚本里面执行 echo "1";访客的浏览器里面就会显示"1". 但是我们执行下面的代码的时候,并不是显示"1&quo ...
- DTLS 技术要点解析
一.DTLS DTLS 是指 Datagram Transport Level Security,即数据报安全传输协议: 其提供了UDP 传输场景下的安全解决方案,能防止消息被窃听.篡改.身份冒充等问 ...
- C#中let字句
应用场景: 在查询表达式中,存储子表达式的结果有时很有用,这样可以在随后的子句中使用. 可以使用 let 关键字完成这一工作,该关键字可以创建一个新的范围变量,并且用您提供的表达式的结果初始化该变量. ...