定义

在 Java 中,内部类是一种特殊的类,它定义在另一个类的内部

内部类的分类:成员内部类(静态、非静态)vs 局部内部类(方法内、代码块内、构造器内)

成员内部类

成员内部类可以是静态的或非静态的。静态内部类不能访问外部类的非静态成员,但可以访问外部类的静态成员。非静态内部类可以访问外部类的所有成员。

下面是一个示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.base.learn;

public class OuterClass {
private int x = 10;
static int y = 20;

// 静态内部类
static class StaticInnerClass {
public void print() {
// 不能访问外部类的非静态成员
System.out.println("Static Inner Class: y = " + y);
}
}

// 非静态内部类
class InnerClass {
public void print() {
System.out.println("Inner Class: x = " + x + ", y = " + y);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.base.learn;

public class Main {
public static void main(String[] args) {
// 创建静态内部类的实例
OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
staticInner.print();

// 创建非静态内部类的实例
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
inner.print();
}
}

输出

1
2
Static Inner Class: y = 20
Inner Class: x = 10, y = 20

内部类常用于实现回调

局部内部类

在 Java 中,局部内部类是一种特殊的内部类,它定义在方法内部。局部内部类只能在定义它的方法内部访问,不能在方法外部访问。局部内部类也可以访问外部类的所有成员,包括私有成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.base.learn;

public class OuterClass2 {
private int x = 10;
static int y = 20;

public void method() {
// 局部内部类
class LocalInnerClass {
public void print() {
// 可以访问外部类的所有成员
System.out.println("Local Inner Class: x = " + x + ", y = " + y);
}
}

// 创建局部内部类的实例
LocalInnerClass inner = new LocalInnerClass();
inner.print();
}
}
1
2
3
4
5
6
7
8
9
package com.base.learn;

public class Main2 {
public static void main(String[] args) {
OuterClass2 outer = new OuterClass2();
outer.method();
}
}

输出

1
Local Inner Class: x = 10, y = 20

局部内部类常用于在方法内部创建类,并且只在方法内部使用

有个注意的点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.base.learn;

public class OuterClass2 {
private int x = 10;
static int y = 20;

public void method() {
int num = 10;

// 局部内部类
class LocalInnerClass {

public void print() {
/**
* 在局部内部类的方法中(比如:print)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话
* 要求此局部变量声明为final的.
* jdk 7及之前版本:要求此局部变量显式的声明为final的
* jdk 8及之后的版本:可以省略final的声明
*
*/
// num = 30; // Variable 'num' is accessed from within inner class, needs to be final or effectively final

// 可以访问外部类的所有成员
System.out.println("Local Inner Class: x = " + x + ", y = " + y);
}
}

// 创建局部内部类的实例
LocalInnerClass inner = new LocalInnerClass();
inner.print();
}
}

匿名内部类

在 Java 中,匿名内部类(Anonymous Inner Class)是没有名称的内部类,通常用于简化代码结构,特别是在需要创建只有一次使用的小类时。匿名内部类通常用于实现接口或继承类,并且可以在方法内部、代码块内部或者表达式中定义。

匿名内部类的使用场景

  • 实现接口:当只需要实现接口的某些方法时,而不想为此创建一个单独的类。
  • 继承类:继承一个类并重写它的方法,且不希望创建一个新的子类文件。
  • 简化代码:适用于仅在某一处需要特定功能或逻辑的场景,不必定义额外的类文件。

语法格式

匿名内部类通常以一种表达式的形式存在,具体语法如下:

  1. 继承类的匿名内部类
1
2
3
new 父类构造器() {
// 重写父类的方法
};
  1. 实现接口的匿名内部类
  2. 1
    2
    3
    new 接口名() {
    // 实现接口中的方法
    };

实现接口的匿名内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) {
// 使用匿名内部类实现 Runnable 接口
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类实现了 Runnable 接口");
}
};

Thread thread = new Thread(runnable);
thread.start();
}
}

继承类的匿名内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
public static void main(String[] args) {
// 使用匿名内部类继承类
Animal animal = new Animal() {
@Override
public void makeSound() {
System.out.println("匿名内部类继承了 Animal 类并重写方法");
}
};
animal.makeSound();
}
}

class Animal {
public void makeSound() {
System.out.println("Animal 的声音");
}
}

匿名内部类的限制

  1. 无法拥有构造器:因为匿名内部类没有类名,因此不能定义构造器。
  2. 只能访问局部的 finaleffectively final变量:如果匿名内部类要访问外部的局部变量,这些变量必须是 finaleffectively final(实际上不会被修改的变量)。
  3. 不能声明静态成员:匿名内部类不能包含静态方法或静态变量(除非是常量)。

匿名内部类的简洁性和临时性使它非常适合处理简单的实现需求,如事件监听器、回调函数等。