【Java基础】内部类 (成员内部类、局部内部类、静态内部类、匿名内部类)

【Java基础】内部类 (成员内部类、局部内部类、静态内部类、匿名内部类)

内部类是什么呢?

Java内部类,是定义在一个类内部的类。在Java编程语言中,内部类是一个十分独特且强大的结构,它允许在一个外部类的内部定义另一个类。这种结构不仅增加了代码的封装性,还提供了访问外部类的私有成员的能力,从而在某些情况下简化了代码设计。

内部类的概念:

内部类是指在一个外部类的内部定义的类。它可以访问包含它的外部类的所有成员,包括私有成员。内部类可以定义为非静态或静态。非静态内部类持有外部类的引用,而静态内部类则不需要。

内部类的分类:

成员内部类、局部内部类、静态内部类、匿名内部类

一、成员内部类

概念

成员内部类(Member Inner Class)是指在一个外部类的内部定义的类。成员内部类和外部类有着紧密的联系,能够访问外部类的所有成员,包括私有成员。成员内部类通常用来逻辑上关联外部类,并且可以更好地封装数据和行为。

特点

访问权限:成员内部类可以访问外部类的所有成员(包括私有成员)。与外部类实例的关联:成员内部类的实例与创建它的外部类实例相关联。要创建成员内部类的实例,必须首先创建一个外部类的实例。外部类引用:成员内部类可以使用 OuterClass.this来引用外部类的实例。

public class OuterClass {

private String name = "外部类";

public void printName() {

System.out.println("外部类名称: " + name);

}

class InnerClass {

public void accessOuterClass() {

System.out.println("内部类访问外部类成员:");

System.out.println("外部类名称: " + OuterClass.this.name);

OuterClass.this.printName();

}

}

public static void main(String[] args) {

OuterClass outer = new OuterClass();

OuterClass.InnerClass inner = outer.new InnerClass();

inner.accessOuterClass();

}

}

在这个例子中,InnerClass通过OuterClass.this.name和OuterClass.this.printName()访问了外部类OuterClass的成员变量和方法。

实例化方式:要实例化成员内部类,必须先实例化外部类,然后使用外部类的实例来实例化内部类。

成员内部类是定义在外部类中的类,并且与外部类的实例相关联。它们可以访问外部类的所有成员,包括私有成员。使用成员内部类可以使相关类之间的关系更加紧密,并且有助于封装和组织代码。

代码实现

public class OuterClass {

private String outerField = "Outer Field";

// 成员内部类

class InnerClass {

private String innerField = "Inner Field";

// 内部类的方法

public void display() {

// 访问外部类的成员

System.out.println("Outer Field: " + outerField);

// 访问内部类的成员

System.out.println("Inner Field: " + innerField);

}

}

// 外部类的方法,用于创建和使用内部类的实例

public void useInnerClass() {

InnerClass inner = new InnerClass();

inner.display();

}

public static void main(String[] args) {

// 创建外部类的实例

OuterClass outer = new OuterClass();

// 使用外部类的方法来使用内部类

outer.useInnerClass();

// 直接创建内部类的实例

OuterClass.InnerClass innerDirect = outer.new InnerClass();

innerDirect.display();

}

}

二、局部内部类

概念

局部内部类(Local Inner Class)是定义在一个方法、构造器或代码块中的类。局部内部类只能在其定义的范围内使用,并且通常用于封装仅在该方法中需要的逻辑。局部内部类可以访问外部类的成员变量和方法,但外部类不能直接访问局部内部类的成员。

特点

局部内部类只能访问外部类的 final 变量或者实际上不变的变量。局部内部类可以直接访问外部类的成员,包括私有成员。局部内部类不能含有 static 的变量和方法。注意事项

局部内部类的定义必须在方法内部,不能在类的其他部分定义。局部内部类的对象创建时机是在方法调用时,随方法执行完毕而销毁。代码实现

// 定义一个名为OuterClass的外部类

public class OuterClass {

// 定义一个私有成员变量name,并初始化为"外部类"

private String name = "外部类";

// 定义一个公共方法printName(),用于打印name的值

public void printName() {

System.out.println("外部类名称: " + name);

}

// 定义一个公共方法method()

public void method() {

// 在method()方法中定义一个局部内部类LocalInnerClass

class LocalInnerClass {

// 定义一个私有成员变量innerName,并初始化为"局部内部类"

private String innerName = "局部内部类";

// 定义一个公共方法printInnerName(),用于打印innerName和访问外部类成员

public void printInnerName() {

System.out.println("局部内部类名称: " + innerName);

System.out.println("访问外部类成员: " + name);

printName();

}

}

// 创建LocalInnerClass的一个实例localInner

LocalInnerClass localInner = new LocalInnerClass();

// 调用localInner的printInnerName()方法

localInner.printInnerName();

}

// 定义主方法main()

public static void main(String[] args) {

// 创建OuterClass的一个实例outer

OuterClass outer = new OuterClass();

// 调用outer的method()方法

outer.method();

}

}

这段代码定义了一个名为OuterClass的外部类,其中包含一个私有成员变量name和一个公共方法printName()。在method()方法中,定义了一个局部内部类LocalInnerClass,该类包含一个私有成员变量innerName和一个公共方法printInnerName()。在main()方法中,创建了OuterClass的一个实例outer,并调用其method()方法。

三、静态内部类

概念

静态内部类(Static Nested Class)是在外部类中使用 static 修饰符定义的内部类。与非静态内部类不同,静态内部类不需要外部类的实例即可创建。静态内部类通常用于外部类的逻辑分组,并且可以访问外部类的静态成员。静态内部类是定义在另一个类中的静态类。它类似于顶级类,但被嵌套在另一个类中。静态内部类不依赖于外部类的实例,可以直接创建。

特点

无需外部类实例: 静态内部类的实例可以独立于外部类的实例创建。

访问外部类的静态成员: 静态内部类只能访问外部类的静态成员(变量和方法),不能直接访问外部类的非静态成员。

类似于顶级类: 静态内部类在许多方面类似于顶级类,但它们可以被嵌套在其他类中,用于逻辑分组。

注意事项

成员访问限制: 静态内部类不能直接访问外部类的非静态成员。如果需要访问,可以通过外部类的实例来实现。

静态上下文: 静态内部类本身是在静态上下文中定义的,因此它的所有直接成员(字段和方法)也必须是静态的,除非在实例方法中访问。

代码实现

public class OuterClass {

private static String staticOuterField = "Static Outer Field";

private String instanceOuterField = "Instance Outer Field";

// 静态内部类

public static class StaticInnerClass {

private String innerField = "Inner Field";

public void display() {

// 访问外部类的静态成员

System.out.println("Static Outer Field: " + staticOuterField);

// 不能直接访问外部类的非静态成员

// System.out.println("Instance Outer Field: " + instanceOuterField); // 错误

}

// 静态内部类中的静态方法

public static void staticDisplay() {

// 访问外部类的静态成员

System.out.println("Static Outer Field: " + staticOuterField);

}

}

public static void main(String[] args) {

// 创建静态内部类的实例

StaticInnerClass inner = new StaticInnerClass();

inner.display();

// 调用静态内部类的静态方法

StaticInnerClass.staticDisplay();

}

}

这段代码定义了一个名为OuterClass的外部类,其中包含一个静态成员变量staticOuterField和一个实例成员变量instanceOuterField。在OuterClass中还定义了一个静态内部类StaticInnerClass,该类包含一个成员变量innerField和两个方法display()和staticDisplay()。在main()方法中,创建了StaticInnerClass的一个实例inner,并调用了其display()方法和StaticInnerClass的静态方法staticDisplay()。

四、匿名内部类

概念

匿名内部类(Anonymous Inner Class)是没有名字的内部类,通常用于简化代码,只在某个特定场景下使用一次。匿名内部类可以用来继承一个类或实现一个接口。匿名内部类定义在方法、构造器或初始化块中,用于即时实例化一个对象。匿名内部类通常用于需要快速创建类的实例并覆盖其方法的情况。

特点

没有名字: 匿名内部类没有名字,不能在其他地方引用或复用。

一次性使用: 匿名内部类通常只在创建它的地方使用一次。

简化代码: 匿名内部类可以直接定义在使用它们的地方,减少了定义新类的繁琐步骤。

可以继承一个类或实现一个接口: 匿名内部类可以用来继承一个现有的类或实现一个接口。

注意事项

访问局部变量: 匿名内部类可以访问包含它的作用域中的局部变量,但这些变量必须是 final 或有效 final。

构造器: 匿名内部类没有构造器,可以通过初始化块来初始化实例变量。

限制: 由于匿名内部类没有名字,不能在定义之外的其他地方引用或复用它们。

匿名内部类是一种简化代码的方式,用于即时创建类的实例并覆盖其方法。它没有名字,通常只在创建它的地方使用一次。匿名内部类可以继承一个类或实现一个接口,可以访问外部类的成员变量和包含它的局部变量(这些变量必须是 final 或有效 final)。匿名内部类在简化代码、封装临时逻辑方面非常有用。

代码实现

public class OuterClass {

private String outerField = "Outer Field";

public void outerMethod() {

final String localVar = "Local Variable"; // 局部变量,必须是 final 或有效 final

// 使用匿名内部类创建线程

Thread thread = new Thread() {

@Override

public void run() {

// 访问外部类的成员

System.out.println("Outer Field: " + outerField);

// 访问局部变量

System.out.println("Local Variable: " + localVar);

}

};

thread.start();

// 使用匿名内部类实现接口

Runnable runnable = new Runnable() {

@Override

public void run() {

// 访问外部类的成员

System.out.println("Outer Field: " + outerField);

// 访问局部变量

System.out.println("Local Variable: " + localVar);

}

};

new Thread(runnable).start();

}

public static void main(String[] args) {

OuterClass outer = new OuterClass();

outer.outerMethod();

}

}

上述代码使用匿名内部类实现接口:

// 使用匿名内部类实现接口

Runnable runnable = new Runnable() {

@Override

public void run() {

// 访问外部类的成员

System.out.println("Outer Field: " + outerField);

// 访问局部变量

System.out.println("Local Variable: " + localVar);

}

};

new Thread(runnable).start();

匿名内部类:这里定义了一个实现 Runnable 接口的匿名内部类,并重写了其 run 方法。该匿名内部类在创建的同时定义并实例化。访问外部类成员:匿名内部类能够直接访问外部类的私有成员 outerField。访问局部变量:匿名内部类能够访问方法内的局部变量 localVar,因为它是 final 的。启动线程:创建一个新的 Thread 实例,并将 Runnable 类型的匿名内部类实例 runnable 传递给 Thread 构造器,随后调用 start 方法启动线程,这会调用 run 方法。总结

成员内部类适合在需要访问外部类的实例成员时使用,必须通过外部类的实例创建。

局部内部类适合在方法内部使用,需要局部类逻辑封装时使用,局部变量需 final。

静态内部类适合在不需要外部类实例的情况下使用,可以直接访问外部类的静态成员。

匿名内部类适合临时实现一个类或接口,通常用于简化代码和一次性使用的场景。

每种内部类都有其特定的使用场景和限制,合理使用内部类可以使代码更加简洁和具有层次性。

希望本文对你理解和使用Java内部类提供了帮助。如果你有任何问题或建议,请随时留言。

相关尊享内容