Java 内部类
一 含义
在 Java 编程语言里, 程序是由类 (class) 构建而成的在一个类的内部也可以声明类, 我们把这
样的类叫做内部类
二 作用
实现了更好的封装, 我们知道, 普通类 (非内部类) 的访问修饰符不能为 private 或 protected, 而内部类可以当我们将内部类声明为 private 时, 只有外部类可以访问内部类, 很好地隐藏了内部类
内部类可以继承 (extends) 或实现 (implements) 其他的类或接口, 而不受外部类的影响
内部类可以直接访问外部类的字段和方法, 即使是用 private 修饰的, 相反的, 外部类不能直接访问内部类的成员
三 原理
内部类是一个编译时的概念, 编译后会生成两个独立的 class 文件, 如下:
- public class Outer{
- private String outerName = "outer";
- class Inner{
- private String innerName = "inner";
- }
- }
编译后的文件如下图:
编译后 Outer.Inner 被重命名为 Outer$Inner, 句点 (.) 被替换成了美元符号($)
四 分类
Java 内部类可分为成员内部类局部内部类匿名内部类静态内部类
1) 成员内部类
成员内部类可以看成是外部类的一个成员, 在成员内部类中无法声明静态成员, 但 static
final 字段是个例外我们知道加载类时, 会先初始化静态成员, 如果成员内部类有静态成
员, 那么内部类就会在外部类之前生成, 而内部类是为外部类服务的, 内部类在外部类之
前就生成可能会脱离掌控在实例化成员内部类时, 成员内部类会持有一个外部类当前对
象的引用, 这样在成员内部类中就可以直接访问外部类的成员, 即使是 private 修饰的
- import static java.lang.System.out;
- public class Outer{
- private String outerName = "outer";
- // 外部类无法直接访问内部类的成员, 需要实例化内部类对象
- private Inner inner = new Inner();
- public class Inner{
- private String innerName = "inner";
- public void show(){
- out.println(outerName); // 可以直接访问外部类的成员
- }
- }
- public void show(){
- out.println(inner.innerName);
- inner.show();
- }
- public static void main(String[] args){
- Outer outer = new Outer();
- outer.show();
- // 实例化内部类
- Outer.Inner inner = outer.new Inner();
- inner.show();
- }
- }
运行结果:
- inner
- outer
- outer
成员内部类对外部类对象的引用, 是通过在 this 前面加上外部类的名字构成的, 这种形式叫作
限定 - this,out.println(outerName)与 out.println(Outer.this.outerName)是等价的
2) 局部内部类
局部内部类的使用和成员内部类的使用基本一致, 只是局部内部类定义在外部类的方法中, 就
像局部变量一样, 并不是外部类的成员局部内部类在方法外是无法访问到的, 但它的实例可
以从方法中返回, 并且实例在不再被引用之前会一直存在局部内部类也可以访问所在方法的
局部变量方法参数等, 限制是局部变量或方法参数只有在声明为 final 时才能被访问
- import static java.lang.System.out;
- public class Outer{
- private String outerName = "outer";
- public void show(final String str){ // 方法参数为 final 类型
- class Inner{
- public void print(){
- out.println(outerName+str);
- }
- }
- Inner inner = new Inner();
- inner.print();
- }
- public static void main(String[] args){
- Outer outer = new Outer();
- outer.show(":lalala");
- }
- }
运行结果:
outer:lalala
3) 匿名内部类
可以把匿名内部类想象成是没有类名的局部内部类, 匿名内部类有以下特点:
1 匿名内部类不能有构造器, 匿名内部类没有类名, 肯定无法声明构造器
2 匿名内部类必须继承或实现一个接口, 指定给 new 的类型为匿名类的超类型, 匿名类不
能有显示的 extends 或 implements 子句, 也不能有任何修饰符
3 匿名内部类和成员内部类局部内部类一样, 也不能声明静态成员
- import static java.lang.System.out;
- public class Outer{
- private String outerName = "outer";
- public void show(final String str){
- new Inner(){ // 实现了 Inner 接口
- public void print(){
- out.println(outerName+str);
- }
- }.print();
- }
- public static void main(String[] args){
- Outer outer = new Outer();
- outer.show(":lalala");
- }
- }
- interface Inner{
- void print();
- }
运行结果:
outer:lalala
4) 静态内部类
静态内部类, 有的书上也称为嵌套类, 声明它时需要用 static 修饰符, 静态内部类不同于前三
种内部类, 静态内部类不会持有外部类当前对象的引用, 所以在静态内部类中无法访问外部
类的非静态成员, 可以这么说, 静态内部类不依赖于外部类
- import static java.lang.System.out;
- public class Outer{
- private String outerName = "outer";
- private static int id = 123;
- private Inner inner = new Inner();
- public static class Inner{
- public void print1(){
- //out.println(outerName); 无法访问外部类的非静态成员
- out.println(id);
- }
- public static void print2(){
- out.println(id);
- }
- }
- public void show(){
- inner.print1();
- }
- public static void main(String[] args){
- Outer outer = new Outer();
- outer.show();
- Outer.Inner.print2(); // 直接通过类名访问静态内部类
- }
- }