目录
1. 何为内部类
2. 内部类的分类
2.1 静态内部类
2.1.1 如何实例化静态内部类的对象?
2.1.2 外部类与静态内部类如何相互访问?
2.2 非静态内部类/实例内部类
2.2.1 非静态内部类不能定义静态的成员变量以及方法
2.2.2 非静态内部类的实例化
2.2.3 外部类与非静态内部类的互相访问
2.2.4 当内外部类的成员变量名字相同时
2.3 局部内部类
2.4 匿名内部类
1. 何为内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,称为内部类。内部类也是封装的一种体现。
2. 内部类的分类
2.1 静态内部类
被 static 修饰的内部成员类称为静态内部类。
class OutClass {
//静态内部类:
static class InnerClass{
}
}
2.1.1 如何实例化静态内部类的对象?
public static void main(String[] args) {
//实例化一个内部类对象;
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
}
2.1.2 外部类与静态内部类如何相互访问?
1. 静态内部类访问外部类成员:
class OuterClass{
public int a = 1;
private int b = 2;
public static int c = 3;
static class InnerClass {
public int d = 4;
private int e = 5;
public static int f = 6;
public void func(){
System.out.println("static->InnerClass::func");
System.out.println(a); //红字报错!!
System.out.println(b); //红字报错!!
System.out.println(c);
System.out.println(d);
System.out.println(e);
System.out.println(f);
}
}
}
由前面学过的知识可知,所有 static 修饰的,都不依赖于对象,但如果没有 static 修饰,就一定得实例化对象之后才能访问。所以在静态内部类内部直接访问外部类的非静态成员是不行的,得实例化对象才行:
//将上述代码注释处修改为:
OuterClass outerClass = new OuterClass();
System.out.println(outerClass.a);
System.out.println(outerClass.b);
调用 func 方法:
public static void main(String[] args) {
//实例化一个内部类对象;
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
innerClass.func();
}
2. 外部类访问静态内部类成员:
在外部类中,写这样一个方法:
发现,外部类方法直接访问内部类成员,全部红字报错,该如何修改?
public void outerFunc(){
System.out.println("OuterClass::outerFunc");
InnerClass innerClass = new InnerClass();
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(innerClass.d); //d 为静态内部类非静态成员变量
System.out.println(innerClass.e); //e 为静态内部类非静态成员变量
System.out.println(InnerClass.f); //f 是静态内部类的静态成员变量,通过类名便可访问
}
注意:内部类和外部类共用同一个 java 源文件,但是经过编译之后,内部类会形成单独的字节码文件:
2.2 非静态内部类/实例内部类
public class OutClass {
class InnerClass{
}
}
// OutClass是外部类
// InnerClass是非静态内部类
2.2.1 非静态内部类不能定义静态的成员变量以及方法
但如果非要有,加个 final :
加了 final ,f 变成常量,而常量在程序编译过程中,是一个确定的值。
2.2.2 非静态内部类的实例化
public static void main(String[] args) {
OuterClass1 outerClass = new OuterClass1();
OuterClass1.InnerClass1 innerClass1 = outerClass.new InnerClass1();
System.out.println(innerClass1.d);
}
在此也可以看出,非静态内部类相较静态内部类麻烦, 需要实例化外部类的对象。一般情况下,使用静态内部类较多。
2.2.3 外部类与非静态内部类的互相访问
1. 非静态内部类访问外部类:
class OuterClass1{
public int a = 1;
private int b = 2;
public static int c = 3;
class InnerClass1{
public int d = 4;
private int e = 5;
public static final int f = 6;
public void func(){
System.out.println("InnerClass1::func");
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(e);
System.out.println(f);
}
}
}
public class Text {
public static void main(String[] args) {
OuterClass1 outerClass = new OuterClass1();
OuterClass1.InnerClass1 innerClass1 = outerClass.new InnerClass1();
innerClass1.func();
}
}
2. 外部类访问非静态内部类:
public void func1(){
System.out.println("OuterClass1::func1");
InnerClass1 innerClass1 = new InnerClass1();
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(innerClass1.d);
System.out.println(innerClass1.e);
System.out.println(innerClass1.f);
}
2.2.4 当内外部类的成员变量名字相同时
class OuterClass2{
public int a = 4;
class InnerClass2{
public int a = 444444;
public void func(){
System.out.println(a);
}
}
}
调用 func 时会输出 444444
那如果非要输出外部类的 a ,该如何?
System.out.println(OuterClass2.this.a);
在非静态外部类中,包含两个 this,一个是自己的 this ,一个是代表外部类对象的引用,像上面代码写的,OuterClass2.this.a
2.3 局部内部类
定义在外部类的方法体或者{ }中,该种内部类只能在其定义的位置使用,一般使用的非常少,此处简单了解下语法格式。
class OutClass3{
public void func(){
class InnerClass3{
public int a = 8;
public void fun(){
System.out.println("hello!");
}
}
InnerClass3 innerClass3 = new InnerClass3();
innerClass3.fun();
}
}
public class Text {
public static void main(String[] args) {
OutClass3 outClass3 = new OutClass3();
outClass3.func();
}
}
【注意事项】
1. 局部内部类只能在所定义的方法体内部使用
2. 不能被public、static等修饰符修饰
3. 编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class
4. 几乎不会使用
2.4 匿名内部类
接口是不能实例化的,需要借助一个具体类,如:
interface IA{
void func();
}
class AA implements IA{
public void func(){
System.out.println("hehehe");
}
}
public class Text {
public static void main(String[] args) {
IA ia = new AA();
ia.func();
}
}
而匿名内部类可以实现跟 class AA 一样的功能:
public static void main(String[] args) {
new IA(){
@Override
public void func() {
System.out.println("呜呜呜~");
}
};
}
匿名内部类也意味着,这是一个实现了 IA 这个接口,并且重写了 func 方法的类。
那如何调用呢?很简单:
public static void main(String[] args) {
new IA(){
@Override
public void func() {
System.out.println("呜呜呜~");
}
}.func();
}
此时的匿名内部类是没有字节码文件的。