什么事
在类内部定义的类,称为内部类(是否累了),如下所示:
公共类a {
隐私Int c=1;
公共类c {
公共语音测试(
系统. out.println (c : ) c;
}
}
}
c被称为a的内部类,简称内部类
a被称为c的外部类,简称为外部类
而且,内部类可以访问外部类的成员(静态成员、实例成员)当然有一些限制,限制如下
四种宣言方式
根据内部类的声明方法,可以分为四种内部类。
静态内部类
声明为类的静态成员的类称为“静态内部类”
公共类a {
私有静态字符串b=' b ';
隐私Int c=1;
//B是a的静态内部类
公共静态类b {
公共语音测试(
系统. out.println (b );
}
}
}
静态内部类,只能访问外部类的静态成员(方法和变量),并且可以像类的成员一样使用修饰符(public/protected/private )
如何创建静态内部类对象: A.B b=new A.B (;
成员内部类
非静态限定的新类的实例成员声明的类称为“成员内部类”
公共类a {
私有静态字符串b=' b ';
隐私Int c=1;
//C是a的成员内部类
公共类c {
公共语音测试(
系统. out.println (c;
系统. out.println (b );
}
}
}
可以访问所有成员内部类、外部类(静态类还是实例类),并使用修饰符(public/protected/private ),如成员方法和类成员
如何在成员内部创建类对象:
A a=new A (;
A.C c=a.new C (;
方法内部类
在一个代码块中声明的类称为方法内部类,代码块包含“在方法中、在静态代码块中和在实例代码块中”
公共类a {
私有静态字符串b;
隐私Int c;
//成员方法
公共语音测试(
final int d=1;
//方法内部类
类d {
公共语音测试(
//访问静态变量
系统. out.println (b );
//访问实例变量
系统. out.println (c;
//访问方法final型局部变量
系统. out.println (d;
}
}
}
}
方法内部类及其所在的方法(代码块)具有相同的访问能力。 如果上面的代码是用static方法声明的,则内部类d无法访问c变量。
jdk1.8方法内部类可以访问非final类型的局部变量,本质上是在内部类d中存储副本
匿名内部类
匿名内部类,即未命名的内部类
因为没有名称,所以匿名内部类只能使用一次。 通常用于简化代码的编写
但是,要使用匿名内部类,还必须继承父类或实现接口,这也是前提条件
内部类的本质
内部类的语法很奇怪,让我们来看看下面的代码。 编译的字节码文件!
公共类a {
私有静态字符串b=' b ';
隐私Int c=1;
//静态内部类
公共静态类b {
公共语音b () {
系统. out.println (b );
}
}
//成员内部类
类c {
公共语音c (}
系统. out.println (c;
}
}
}
A.java文件已编译成多个class文件
a类对应于A.class
b类对应于A$B.class
c类对应于A$C.class
内部类编译为单独的class文件。 这意味着JVM类“b”和a类在运行class文件时是独立的。 由此可见,内部类也是语法糖。
对JVM来说,a类private b和c类成员为什么可以分别访问b类和c类!
让我们用javap命令反编译A.class类。
秘密是编译器为外部类生成的两种静态访问方法,其中Stinrg access$000 (返回b变量的值,intaccess$100 ) a返回a对象的c成员变量的值。
在静态内部类b中,编译器用上述方法替换访问静态变量b的位置。
//静态内部类
公共静态类a $ b {
公共语音b () {
system.out.println (a.access $ 000 ) );
}
}
在成员内部类c中,原理相同,但添加了更多,并反向编译A$C.class:
成员字段final A $this;
构建方法形式参考` a$c(aobj );
访问外部类成员变量的位置将替换为: system.out.println (a.access $ 100 ) $this )。
你一定很好奇成员构建方法的外部类对象的参数是从哪里进来的! 让我们看看如何声明内部类的对象
A a=new A (;
A.C c=a.new C (;
它将被编译器取代。
A a=new A (;
a$cc=newa$c(a );
内部类的使用时机
如果两个类密切相关,则可以使用内部类。
如果一个类需要访问另一个类的许多属性,内部类可以简化访问代码
为了实现更好的封装,例如,如果b类仅由a类访问,则b类可以是a类的专用内部类
代码简洁,匿名内部类