JavaSE:面向对象进阶之内部类(Inner Class)
JavaSE 面向对象进阶之内部类(Inner Class)
一、内部类的核心概念
内部类是定义在另一个类内部的类,它与外部类存在紧密的逻辑关联,主要作用:
- 封装细节:隐藏实现细节,对外提供简洁接口。
- 访问权限:可访问外部类的私有成员(包括属性和方法)。
- 逻辑分组:将相关类组织在同一文件中,提高代码内聚性。
二、内部类的四种形式
1. 成员内部类
- 定义:作为外部类的成员存在,与属性、方法同级。
- 特点:
- 可使用
public
、private
等访问修饰符。 - 持有外部类的引用:
OuterClass.this
。
- 可使用
- 示例:
public class Outer {private int x = 10;public class Inner {public void printX() {System.out.println(Outer.this.x); // 访问外部类私有属性}}public Inner getInner() {return new Inner(); // 创建内部类对象}
}// 创建内部类实例
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // 必须通过外部类实例创建
2. 静态内部类
- 定义:使用
static
修饰的内部类,不依赖外部类实例。 - 特点:
- 只能访问外部类的静态成员。
- 可直接创建实例:
new Outer.StaticInner()
。
- 示例:
public class Outer {private static int x = 10;public static class StaticInner {public void printX() {System.out.println(x); // 只能访问静态成员}}
}// 创建静态内部类实例
Outer.StaticInner inner = new Outer.StaticInner();
3. 局部内部类
- 定义:定义在方法或代码块内部的类,作用域仅限于该区域。
- 特点:
- 不能使用访问修饰符(如
public
)。 - 可访问外部类成员及方法的
final
局部变量(Java 8+ 可省略final
,但变量必须实际不可变)。
- 不能使用访问修饰符(如
- 示例:
public class Outer {public void method() {final int y = 20; // 局部变量(Java 8+ 可省略final)class LocalInner {public void printY() {System.out.println(y); // 访问局部变量}}LocalInner inner = new LocalInner();inner.printY();}
}
4. 匿名内部类
- 定义:没有显式类名的局部内部类,通常用于创建一次性对象。
- 特点:
- 必须继承一个父类或实现一个接口。
- 没有构造方法,但可通过实例初始化块初始化。
- 示例:
public interface ClickListener {void onClick();
}public class Button {public void setListener(ClickListener listener) {listener.onClick();}
}// 使用匿名内部类实现接口
button.setListener(new ClickListener() {@Overridepublic void onClick() {System.out.println("Button clicked");}
});// Java 8+ 可用Lambda简化(函数式接口)
button.setListener(() -> System.out.println("Button clicked"));
三、内部类的应用场景
-
事件监听:
button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {// 处理事件} });
-
封装辅助类:
- 如
Map.Entry
是Map
的内部接口,用于表示键值对。
- 如
-
实现多继承:
- 通过内部类继承多个父类,间接实现多继承。
四、注意事项
-
内存占用:
- 非静态内部类会持有外部类的强引用,可能导致内存泄漏(如Activity中的匿名内部类)。
-
编译后的命名:
- 内部类编译后生成
Outer$Inner.class
文件(匿名内部类为Outer$1.class
)。
- 内部类编译后生成
-
访问限制:
- 静态内部类无法直接访问外部类的非静态成员。
五、面试常见问题
-
内部类有哪些类型?
- 成员内部类、静态内部类、局部内部类、匿名内部类。
-
匿名内部类能否有构造方法?
- 不能,但可通过实例初始化块实现类似构造逻辑。
-
为什么局部内部类和匿名内部类只能访问
final
局部变量?- Java 8之前要求显式声明
final
,之后可省略但变量必须实际不可变。这是为保证变量的生命周期与内部类对象一致(变量值被复制到内部类中)。
- Java 8之前要求显式声明
六、最佳实践
- 优先使用静态内部类:减少内存占用,避免潜在的内存泄漏。
- 避免深层嵌套:内部类层次过深会降低代码可读性。
- 合理使用匿名内部类:适用于简单实现,复杂逻辑建议使用具名类。
内部类是Java语言的重要特性,它增强了类的封装性和代码的灵活性,尤其在GUI编程和设计模式(如迭代器模式)中广泛应用。