【Java】内部类
Java 内部类嵌套于其他类中,分四类,可便捷访问外部类成员,提升封装性,适用于耦合逻辑处理,是重要特性。
内部类
内部类分为四种:静态内部类、实例内部类、匿名内部类、局部内部类四种
1. 静态内部类
1.1 静态内部类的基本语法
public class OuterClass {// 静态内部类public static class StaticNestedClass {// 成员变量和方法}
}
1.2 静态内部类的特性
1.静态内部类不依赖于外部类的实例,它属于外部类本身(而非外部类的某个对象)。因此,无需创建外部类实例,即可直接创建静态内部类的实例。
2.静态内部类可以访问外部类的静态成员(静态变量、静态方法),包括 private 修饰的静态成员。但是静态内部类不能直接访问外部类的非静态成员(因为非静态成员依赖于外部类实例,而静态内部类不依赖)
3.外部类可以通过静态内部类的类名或实例访问其成员(遵循访问修饰符规则)
4.静态内部类是一个独立的类,编译后会生成单独的字节码文件(命名为 外部类名 $ 静态内部类名.class)。它与外部类的关系更像是 “包含” 而非 “依赖”。
public class Main{}
2. 实例内部类
2.1 实例内部类的基本语法
public class OuterClass {// 实例内部类(非静态内部类)public class InnerClass {// 成员变量和方法}
}
2.2 实例内部类的特性
1.实例内部类的对象必须寄生在外部类的实例中,不能独立存在。创建内部类对象时,需先有外部类对象。
2.可访问外部类的所有成员
3.可以定义与外部类同名的字段或方法,但访问外部类的同名成员时需用 外部类名.this.成员名
4.实例内部类中不能定义static字段、方法或静态内部类(除非是static final常量)。
3. 局部内部类
3.1 局部内部类的示例
public class OuterClass {private int outerNum = 100; // 外部类私有成员public void outerMethod(String msg) {final int localNum = 200;// 定义局部内部类(仅在outerMethod中可见)class LocalInner {private int innerNum = 300; // 内部类成员变量// 内部类方法public void printInfo() {// 访问外部类成员System.out.println("外部类变量:" + outerNum);// 访问方法参数(有效final)System.out.println("方法参数:" + msg);// 访问局部变量(显式final)System.out.println("局部变量:" + localNum);// 访问内部类自身成员System.out.println("内部类变量:" + innerNum);}}// 在方法内创建局部内部类对象并使用LocalInner inner = new LocalInner();inner.printInfo();}public static void main(String[] args) {OuterClass outer = new OuterClass();outer.outerMethod("Hello");// 输出:// 外部类变量:100// 方法参数:Hello// 局部变量:200// 内部类变量:300}
}
3.2 局部内部类的特性
1.仅在定义它的方法或代码块内部可见,外部(包括外部类的其他方法)无法直接访问。
2.局部内部类会隐式依赖所在方法的局部变量和参数,但只能访问被final修饰(或事实上不可变)的局部变量(Java 8 + 允许访问 “有效 final” 变量,即未显式声明final但从未被修改的变量)。
3.局部内部类不能被public、private、protected修饰(因为其作用域已被局部范围限制),但可以用abstract或final修饰。
4.与实例内部类类似,局部内部类中不能定义static字段、方法或静态内部类(除非是static final常量)。
5.可以直接访问外部类的所有成员(包括私有成员),无需额外限定。
4. 匿名内部类
4.1 匿名内部类的基本语法
// 格式:通过父类或接口创建匿名内部类实例父类/接口 变量名 = new 父类/接口(参数列表) {// 匿名内部类的类体[成员变量]; // 可定义成员变量[@Override 方法体]; // 重写父类方法或实现接口方法[实例初始化块]; // 用于初始化(替代构造方法)
};
4.2 匿名内部类的特性
1.定义时不需要声明类名,直接通过 new 父类/接口(参数){…} 的形式创建对象,类名由编译器自动生成
2.匿名内部类必须直接继承一个父类,或实现一个接口,且只能继承一个类或实现一个接口。
3.若实现接口或继承抽象类,必须重写所有抽象方法(因为匿名内部类会直接创建实例,而抽象类 / 接口无法实例化)。
4.通常在创建对象的语句中定义,作用域仅限于当前语句,无法在外部重复使用。
5.可直接访问外部类的所有成员(包括私有成员)。