跳到主要内容

成员内部类与方法内部类

成员内部类

成员内部类类似于类的成员,例如变量或方法。它能够访问外部类的所有变量和方法。

public class OuterClass {
private int x = 10;

class InnerClass {
public void print() {
System.out.println(x); // 访问外部类的变量
}
}

public void createInner() {
InnerClass inner = new InnerClass();
inner.print(); // 创建内部类实例并调用其方法
}
}

在上述示例中,InnerClass 作为 OuterClass 的成员,能够直接访问外部类的私有变量 x。通过 createInner 方法,可以实例化内部类并调用其方法。

方法内部类

方法内部类是在方法内部定义的类。它只能在定义它的方法内部被访问和使用。

方法内部类有以下特点:

  1. 编译后的文件名为外部类名$内部类名.class
  2. 方法内部类可以访问定义它的方法中的局部变量。
  3. 必须在方法内部实例化,并调用相应的方法。
  4. 使用方法内部类时,方法的局部变量必须具有 final 特性。
    • 在 Java 8 之前,必须显式使用 final 关键字修饰。
    • 在 Java 8 及之后,即使未显式声明 final,只要不修改该变量,编译器也会将其视为 final
public class OuterClass {
void outerMethod() {
int number = 100; // 这个变量是 effectively final 的,因为没有被修改

// 局部内部类
class InnerClass {
void printNumber() {
System.out.println("Number is " + number);
}
}

// 创建局部内部类的实例并调用方法
InnerClass inner = new InnerClass();
inner.printNumber();
}

public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.outerMethod();
}
}

在这个例子中,InnerClass 定义在 outerMethod 方法内部,并且可以访问方法中的局部变量 number。由于 number 没有被修改,它被视为 effectively final,因此可以在内部类中使用。

静态内部类

静态内部类只能访问外部类的静态成员。

静态内部类的优势包括:

  1. 不依赖于外部类的实例,避免了外部类实例被垃圾回收时内部类实例的内存泄漏。
  2. 可以直接实例化静态内部类,而无需依赖外部类的实例。
  3. 命名空间更为清晰,语义化更完整,例如 DBManager.DBConnect.test()
  4. 适用于定义外部类中的工具类或辅助类。
public class OuterClass {
private static String staticMessage = "Hello, World!";
private String nonStaticMessage = "Hello, Java!";

public static class StaticNestedClass {
public void printMessage() {
System.out.println(staticMessage); // 访问外部类的静态成员
// System.out.println(nonStaticMessage); // 错误,无法访问外部类的非静态成员
}
}
}

在这个示例中,StaticNestedClass 是一个静态内部类,它只能访问 OuterClass 的静态成员 staticMessage。尝试访问非静态成员 nonStaticMessage 会导致编译错误。

匿名内部类

匿名内部类是在需要实现某个接口或继承某个类时,不需要为该实现创建一个完整的类而使用的一种内部类。它们可以使代码更加简洁,并且可以在定义它们的地方立即看到它们的实现。

接口匿名内部类

当需要实现一个接口但不需要为其创建单独的类时,可以使用接口匿名内部类。

interface Greeting {
void greet();
}

public class Main {
public void sayHello() {
Greeting englishGreeting = new Greeting() {
@Override
public void greet() {
System.out.println("Hello, world!");
}
};
englishGreeting.greet();
}

public static void main(String[] args) {
new Main().sayHello();
}
}

在这个例子中,Greeting 接口通过匿名内部类得到了实现,sayHello 方法中创建了该实现的实例并调用了 greet 方法。

抽象方法匿名内部类

当需要使用一个抽象类,并且只需使用一次该类时,可以选择使用匿名内部类。

abstract class AbstractDisplay {
abstract void display();
}

public class Main {
public static void main(String[] args) {
AbstractDisplay display = new AbstractDisplay() {
@Override
void display() {
System.out.println("Displaying abstract class method");
}
};
display.display();
}
}

在这个示例中,AbstractDisplay 是一个抽象类,通过匿名内部类进行了实现,并在 main 方法中调用了 display 方法。

参数匿名内部类

当需要将一个类的实例作为方法参数传递,而这个类可能在其他地方不会被使用时,可以使用参数匿名内部类。

public class Main {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("New thread created");
}
}).start();
}
}

在这个例子中,Runnable 接口通过匿名内部类得到了实现,并作为参数传递给 Thread 的构造方法。这种方式使得代码更加简洁,且无需为 Runnable 接口创建一个单独的实现类。