在Java中,内部类是一种强大的特性,允许将一个类定义在另一个类的内部。内部类提供了更好的封装性,能够访问外部类的成员,并常用于实现事件监听、适配器模式等场景。本文将深入探讨四种内部类:成员内部类、静态内部类、局部内部类和匿名内部类,帮助读者掌握它们的特性及使用场景。
内部类是定义在另一个类内部的类,可分为以下四种类型:
当一个类的存在完全依赖于另一个类,且其功能无法独立存在时,使用内部类可以更清晰地表达这种“整体-部分”的逻辑关系。以下是具体场景和案例解析:
使用条件:
示例:
汽车的发动机(发动机无法脱离汽车独立运行,其生命周期与汽车绑定):
public class Car {
private String model;
private Engine engine; // 内部类实例
public Car(String model) {
this.model = model;
this.engine = new Engine();
}
// 内部类:发动机
class Engine {
void start() {
System.out.println(model + "的发动机启动"); // 直接访问外部类私有属性
}
}
}
成员内部类是直接定义在外部类的成员位置(与类属性、方法同级)的内部类,属于外部类的一个成员,可被权限修饰符(如private
/public
)控制访问范围。
class Outer {
class Inner {
// 成员变量和方法
}
}
特点:
成员内部类被private
修饰时:在外部类中编写方法,返回内部类对象。
public class Outer {
// 私有成员内部类
private class Inner {
void show() {
System.out.println("私有内部类方法");
}
}
// 对外提供内部类对象
public Inner getInnerInstance() {
return new Inner();
}
}
// 使用
Outer outer = new Outer();
Outer.Inner inner = outer.getInnerInstance(); // 通过方法获取
成员内部类被非私有修饰时:直接通过外部类实例创建内部类对象。
public class Outer {
// 非私有成员内部类
public class Inner {
void show() {
System.out.println("非私有内部类方法");
}
}
}
// 使用
Outer.Inner inner = new Outer().new Inner(); // 直接创建
通过外部类名.this.变量名
显式访问外部类变量。
public class Outer {
int num = 10; // 外部类成员变量
class Inner {
int num = 20; // 内部类成员变量
void print() {
System.out.println("内部类num: " + num); // 输出20(默认访问内部类变量)
System.out.println("外部类num: " + Outer.this.num); // 输出10(显式访问外部类变量)
}
}
}
权限修饰符影响:
private
修饰的成员内部类只能在外部类内部使用,无法被其他类直接访问。public
/protected
/默认权限的成员内部类可被其他类访问,但需遵循权限规则。变量访问优先级:
外部类名.this.变量名
。静态内部类是用static
修饰的成员内部类,其特殊性体现在:
class Outer {
static class StaticInner {
// 静态/非静态成员
}
}
特点:
静态内部类的实例化不依赖外部类对象,直接通过外部类名.内部类名
访问:
Outer.Inner obj = new Outer.Inner();
调用非静态方法:需创建静态内部类对象后调用
// 接上例
Outer.Inner inner = new Outer.Inner();
inner.show(); // 输出"静态内部类方法"
调用静态方法:通过外部类名.内部类名.方法名()
直接访问
public class Outer {
static class Inner {
// 静态方法
static void staticShow() {
System.out.println("静态内部类的静态方法");
}
}
}
// 调用
Outer.Inner.staticShow(); // ✔️无需实例化
访问外部类成员的限制:
public class Outer {
private static int staticVar = 100; // 静态变量
private int instanceVar = 200; // 实例变量
static class Inner {
void access() {
System.out.println(staticVar); // ✔️可以访问
// System.out.println(instanceVar); // ❌编译错误(不能访问实例变量)
}
}
}
在外部类外部使用的导入技巧:
// 导包后简化代码
import com.example.Outer.Inner;
public class Test {
public static void main(String[] args) {
Inner inner = new Inner(); // 仅限静态内部类可这样写
}
}
class Outer {
void method() {
class LocalInner {
void show() {
System.out.println("局部内部类");
}
}
new LocalInner().show();
}
}
匿名内部类是没有显式类名的局部内部类,直接在代码中通过new
关键字定义并实例化。核心特性如下:
Outer$1.class
)。// 继承类
new 父类名() {
// 重写方法
};
// 实现接口
new 接口名() {
// 实现方法
};
// 接口
public interface ClickListener {
void onClick();
}
// 使用匿名内部类实现接口
public class Button {
public void addClick(ClickListener listener) {
// 触发点击逻辑
}
public static void main(String[] args) {
Button button = new Button();
// 匿名内部类作为参数
button.addClick(new ClickListener() {
@Override
public void onClick() {
System.out.println("按钮被点击");
}
});
}
}
特点:
案例:快速接口实现
interface Swim {
void swim();
}
public static void main(String[] args) {
// 直接创建并使用
new Swim() {
@Override
public void swim() {
System.out.println("自由泳");
}
}.swim();
// 作为方法参数
startSwimming(new Swim() {
public void swim() {
System.out.println("蛙泳");
}
});
}
static void startSwimming(Swim s) {
s.swim();
}
类型 | 定义位置 | 访问权限 | 静态成员 | 典型应用场景 |
---|---|---|---|---|
成员内部类 | 类成员位置 | 访问外部类所有成员 | 不允许 | 紧密关联的业务逻辑 |
静态内部类 | 类成员位置 | 只能访问外部类静态成员 | 允许 | 工具类相关功能 |
局部内部类 | 方法内部 | 访问方法final变量 | 不允许 | 方法内部专用实现 |
匿名内部类 | 方法/类内部 | 访问方法final变量 | 不允许 | 单次使用的回调实现 |