成员内部类与方法内部类
成员内部类
成员内部类类似于类的成员,例如变量或方法。它能够访问外部类的所有变量和方法。
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
方法,可以实例化内部类并调用其方法。
方法内部类
方法内部类是在方法内部定义的类。它只能在定义它的方法内部被访问和使用。
方法内部类有以下特点:
- 编译后的文件名为
外部类名$内部类名.class
。 - 方法内部类可以访问定义它的方法中的局部变量。
- 必须在方法内部实例化,并调用相应的方法。
- 使用方法内部类时,方法的局部变量必须具有
final
特性。- 在 Java 8 之前,必须显式使用
final
关键字修饰。 - 在 Java 8 及之后,即使未显式声明
final
,只要不修改该变量,编译器也会将其视为final
。
- 在 Java 8 之前,必须显式使用
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
,因此可以在内部类中使用。
静态内部类
静态内部类只能访问外部类的静态成员。
静态内部类的优势包括:
- 不依赖于外部类的实例,避免了外部类实例被垃圾回收时内部类实例的内存泄漏。
- 可以直接实例化静态内部类,而无需依赖外部类的实例。
- 命名空间更为清晰,语义化更完整,例如
DBManager.DBConnect.test()
。 - 适用于定义外部类中的工具类或辅助类。
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
接口创建一个单独的实现类。