java声明内部类_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);

}

}

}

3c5d74ced733449bdacb3135c1d4f6e4.png

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来看看:

4e846239620a4bb534e13f6dfb0e7799.png

秘密就来自,编译器为外部类生的两个静态访问方法,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:

650e340691f6ee90cbb935c75d3b21b6.png

新增了成员字段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的私有内部类

使代码更简洁,匿名内部类

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值