四种内部类_16
内部类
- 内部类(Inner Class)是指定义在另一个类内部的类。内部类提供了更好的封装性,并且可以访问外部类的成员,包括私有成员
- 内部类主要有四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。
- 内部类的字节码文件会生成在与外部类相同的目录下。
- 成员内部类的字节码文件命名规则为:外部类名$内部类名.class。
- 静态内部类的字节码文件命名规则为:外部类名$内部类名.class
- 匿名内部类的字节码文件命名规则为:外部类名$数字.class。
- 局部内部类的字节码文件命名规则为:外部类名$数字内部类名.class
成员内部类
成员内部类
-
成员内部类是最常见的内部类形式,它定义在外部类的成员位置(即类的内部,但在方法或代码块之外),可以访问外部类的所有成员(包括私有成员),并且它与外部类的实例相关联
public class OuterClass { private int outerField = 10; // 成员内部类 public class InnerClass { public void display() { System.out.println("Outer field value: " + outerField); } } public void otherMethod(){ } }
成员内部类特点
- 成员内部类可以访问外部类的所有成员,包括私有成员
- 成员内部类的实例必须与外部类的实例相关联。也就是说,必须先创建外部类的实例,然后才能创建成员内部类的实例
- 成员内部类不能定义静态成员(除非是静态常量),因为成员内部类的实例与外部类的实例相关联,而静态成员是与类本身相关联的
- 静态常量在编译时就已经确定,并且不会改变
- 成员内部类可以具有不同的访问修饰符(public、protected、private或默认包访问权限),这些修饰符决定了成员内部类在外部类之外的可见性
创建实例
要创建成员内部类的实例,必须先创建外部类的实例,然后使用外部类的实例来创建内部类的实例
public class OuterClass {
private int outerField = 10;
// 成员内部类
public class InnerClass {
public void display() {
System.out.println("Outer field value: " + outerField);
}
}
public static void main(String[] args) {
// 创建外部类的实例
OuterClass outer = new OuterClass();
// 使用外部类的实例创建内部类的实例
OuterClass.InnerClass inner = outer.new InnerClass();
// 调用内部类的方法
inner.display(); // 输出: Outer field value: 10
}
}
使用场景
-
当某个类只在一个类中使用时,可以将其定义为成员内部类,以提高封装性
-
成员内部类的实例持有对外部类实例的引用,因此可以通过
OuterClass.this来访问外部类的实例,如果内部类成员和外部类的成员重名时,就可以使用外部类的实例就可以访问外部类的字段public class OuterClass { private int outerField = 10; public class InnerClass { public void display() { System.out.println("Outer field value: " + outerField); System.out.println("Outer class instance: " + OuterClass.this); } } }
静态内部类
-
静态内部类使用static关键字定义在外部类的内部。与成员内部类不同,静态内部类不依赖于外部类的实例,而是与外部类本身相关联。静态内部类可以访问外部类的静态成员,但不能直接访问外部类的非静态成员
-
静态内部类的定义方式与普通类类似,但它位于外部类的内部,并且使用
static关键字修饰public class OuterClass { private static int outerStaticField = 10; // 外部类的静态成员 private int outerInstanceField = 20; // 外部类的实例成员 // 静态内部类 public static class StaticNestedClass { public void display() { // 可以访问外部类的静态成员 System.out.println("Outer static field: " + outerStaticField); // 不能直接访问外部类的实例成员 // System.out.println("Outer instance field: " + outerInstanceField); // 编译错误 } } }
静态内部类特点
- 静态内部类与外部类的实例无关,因此可以直接创建静态内部类的实例,而不需要先创建外部类的实例
- 静态内部类可以访问外部类的静态成员(静态变量和静态方法),但不能直接访问外部类的非静态成员(实例变量和实例方法)
- 静态内部类可以定义自己的静态成员(静态变量和静态方法),而成员内部类不能定义静态成员(除非是静态常量)
- 静态内部类不能直接访问外部类的实例成员,但可以通过外部类的实例间接访问
创建实例
OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass();
使用场景
-
如果某个类只在一个类中使用,并且不需要访问外部类的实例成员,可以将其定义为静态内部类。例如,Java标准库中的HashMap的Entry类就是一个静态内部类
public class MathUtils { // 静态内部类作为工具类 public static class Calculator { public static int add(int a, int b) { return a + b; } } public static void main(String[] args) { int result = MathUtils.Calculator.add(10, 20); System.out.println("Result: " + result); // 输出: Result: 30 } } -
静态内部类可以隐藏实现细节,提高代码的封装性。例如,可以在静态内部类中实现某个接口或抽象类,而外部类不需要暴露这些细节
局部内部类
-
局部内部类(Local Inner Class)是定义在方法、构造器或代码块中的内部类。它的作用范围仅限于定义它的方法、构造器或代码块,因此局部内部类在外部是不可见的。局部内部类可以访问外部类的成员,但只能访问方法中声明为final或effectively final的局部变量
-
局部内部类定义在方法、构造器或代码块中,它的作用范围仅限于定义它的方法、构造器或代码块
public class OuterClass { public void outerMethod() { // 局部内部类 class Calculator { public int add(int a, int b) { return a + b; } } Calculator calculator = new Calculator(); int result = calculator.add(10, 20); System.out.println("Result: " + result); // 输出: Result: 30 } }
创建实例
-
局部内部类的作用范围仅限于定义它的方法、构造器或代码块。因此,局部内部类的实例化必须在定义它的同一作用域内完成
-
局部内部类是与外部类的实例无关的,它的实例化完全独立于外部类的实例。即使外部类没有实例化,局部内部类也可以在方法内部实例化。(静态方法中可以定义局部内部类)
public class OuterClass { public void outerMethod() { // 定义局部内部类 class LocalInnerClass { public void display() { System.out.println("Inside local inner class."); } } // 创建局部内部类的实例 LocalInnerClass inner = new LocalInnerClass(); inner.display(); // 输出: Inside local inner class. } public static void main(String[] args) { OuterClass outer = new OuterClass(); outer.outerMethod(); } }
局部内部类特点
-
局部内部类的作用范围仅限于定义它的方法、构造器或代码块。在外部无法直接访问局部内部类
-
局部内部类可以访问外部类的所有成员(包括私有成员)
-
局部内部类只能访问该方法中声明为final或effectively final(java8开始为了简化书写)的局部变量。effectively final是指变量在初始化后没有被修改过
-
局部内部类和局部变量一样,不能添加访问修饰符,因为局部变量的生命周期和作用域仅限于方法或代码块,因此不需要像类成员那样使用访问修饰符来控制访问
-
局部内部类不能定义静态成员(静态变量或静态方法),因为局部内部类的作用范围有限,且与类的实例无关
-
局部内部类是与方法调用相关的,它的实例可能只在方法调用期间存在。而静态成员属于类本身,与类的实例无关。由于局部内部类的作用范围和生命周期与静态成员不匹配,Java不允许局部内部类定义静态成员
-
虽然局部内部类不能定义静态变量或静态方法,但它可以定义静态常量(static final变量)。静态常量在编译时就已经确定,并且不会改变,因此Java允许局部内部类定义静态常量
-
局部内部类可以定义在静态方法中,它的作用范围仅限于定义它的静态方法
public void outerMethod() { class LocalInnerClass { // 以下代码会编译错误 // public static int staticVar = 10; // public static void staticMethod() {} } }
局部内部类使用场景
- 如果某个类只在一个方法中使用,并且不需要在外部访问,可以将其定义为局部内部类。这样可以隐藏实现细节,提高代码的封装性
- 如果某个类只在一个方法中使用,并且逻辑较为简单,可以将其定义为局部内部类,从而避免创建额外的类文件
匿名内部类
-
匿名内部类(Anonymous Inner Class)是Java中一种特殊的局部内部类,它没有显式的类名,通常用于创建接口或抽象类的实例。匿名内部类的定义和实例化是在同一语句中完成的,因此它的代码非常简洁,适合用于只需要使用一次的类
new 接口名/父类名() { // 实现接口或父类的方法 };
创建实例
public interface Greeting {
void greet();
}
public class Main {
public static void main(String[] args) {
// 使用匿名内部类实现接口
Greeting greeting = new Greeting() {
@Override
public void greet() {
System.out.println("Hello, world!");
}
};
greeting.greet(); // 输出: Hello, world!
}
}
匿名内部类的特点
-
匿名内部类没有显式的类名,它的定义和实例化是在同一语句中完成的
-
匿名内部类只能实现一个接口或继承一个类,不能同时实现多个接口或继承多个类
-
匿名内部类可以访问外部类的成员(包括私有成员),但只能访问方法中声明为
final或effectively final的局部变量 -
匿名内部类不能定义静态成员(静态变量或静态方法),但可以定义静态常量(static final变量)
-
虽然匿名内部类是一种特殊的局部内部类,成员变量的初始化过程允许使用匿名内部类。匿名内部类的定义和实例化可以发生在成员变量的初始化语句中
-
但是无法单独声明:匿名内部类没有类名,无法像普通类一样先声明后实例化,必须通过 new 关键字与父类/接口结合使用
public class OuterClass { // 正确:匿名内部类可以直接定义在成员变量的位置 /* 但是不能先定义然后在赋值 private Runnable task; task = new Runnable()... //这是错误的 */ private Runnable task = new Runnable() { @Override public void run() { System.out.println("Task is running."); } }; public void executeTask() { new Thread(task).start(); // 输出: Task is running. } public static void main(String[] args) { OuterClass outer = new OuterClass(); outer.executeTask(); } }
匿名内部类使用场景
- 匿名内部类通常用于实现接口,尤其是在只需要使用一次的情况下
- 匿名内部类也可以用于继承抽象类,并实现抽象方法
- 匿名内部类可以简化代码,尤其是在只需要使用一次的类的情况下

浙公网安备 33010602011771号