内部类(Inner classes)

!!! note 目录

内部类

一、实例内部类/成员内部类(Member Inner Class):

  • 成员内部类是定义在外部类的成员位置的类,可以直接访问外部类的所有成员变量和方法,包括私有成员。
  • 成员内部类可以使用访问控制修饰符(如public、private、protected、default)。
  • 外部类可以访问成员内部类的所有成员,但需要先创建内部类的对象
当一个成员内部类(非静态内部类)被定义在外部类中时,外部类可以访问内部类的所有成员,但是需要先创建内部类的对象。下面是一个示例:
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
public class OuterClass {
private int outerMember = 10;

public void outerMethod() {
System.out.println("Outer Method");
}

class InnerClass {
private int innerMember = 20;

public void innerMethod() {
System.out.println("Inner Method");
}
}

public static void main(String[] args) {
OuterClass outer = new OuterClass();
// 创建内部类的对象
OuterClass.InnerClass inner = outer.new InnerClass();

// 外部类可以访问内部类的所有成员
System.out.println(inner.innerMember); // 输出:20
inner.innerMethod(); // 输出:Inner Method
}
}

在这个示例中,InnerClass是一个成员内部类,它被定义在OuterClass中。在main()方法中,首先创建了外部类的实例outer,然后通过该实例创建了内部类的实例inner。接着,外部类可以通过内部类的实例inner访问内部类的所有成员,包括innerMember成员和innerMethod()方法。

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

public class OuterClass {
// 实例变量
public int i = 100;
// 实例方法
public void m1(){
System.out.println("外部类的实例方法m1执行了");
}

// 静态变量
private static int j = 200;
// 静态方法
public static void m2(){
System.out.println("外部类的静态方法m2执行了");
}

// 实例内部类
// 也可以使用访问权限修饰符修饰。
public class InnerClass {
public void x(){
System.out.println(i);
System.out.println(j);
m1();
m2();
}
}

}

1
2
3
4
5
6
7
8
public class OuterClassTest {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
System.out.println(outerClass.i);
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.x();
}
}

二、静态内部类(Static Inner Class)

  • 静态内部类使用 static 关键字修饰,与外部类的实例无关,可以直接访问外部类的静态成员。
  • 静态内部类不能直接访问外部类的非静态成员,但可以通过创建外部类的实例来访问。
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
33
34
35
36
37
38
39
40
41
42
public class OuterClass {

// 静态变量
private static int i = 100;

// 实例变量
private int j = 200;

// 静态方法
public static void m1(){
System.out.println("外部类的m1静态方法执行了");
}

// 实例方法
public void m2(){
System.out.println("外部类的m2实例方法执行了");
}

// 静态内部类
// 对于静态内部类来说:访问控制权限修饰符(public、default、protected、private)在这里都可以使用。
private static class InnerClass {
public void m3(){
System.out.println(i);
//System.out.println(j);
m1();
//m2();
}
public static void m4(){
System.out.println(i);
//System.out.println(j);
m1();
//m2();
}
}

public static void main(String[] args) {
//在类中调用。内部类修饰符可以使private。
InnerClass innerClass2 = new InnerClass();
innerClass2.m3();
InnerClass.m4();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
//在其他类如何调用。(注意内部类修饰符,修饰不当会导致其他类无法访问。)
public class OuterClassTest {
public static void main(String[] args) {
// 创建内部类对象,静态内部类new对象形式。
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
// 调用方法(实例方法,必须创建对象。)
innerClass.m3();

// 调用m4方法(静态方法、用类名调用。)
OuterClass.InnerClass.m4();
}
}

在Java中,静态内部类不能直接访问外部类的非静态成员,但可以通过创建外部类的实例来访问。下面是一个简单的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class OuterClass {
private int outerMember = 10;

public void outerMethod() {
System.out.println("Outer Method");
}

static class StaticInnerClass {
public void innerMethod() {
// 静态内部类不能直接访问外部类的非静态成员
// System.out.println(outerMember); // 这行代码会产生编译错误
}
}

public static void main(String[] args) {
// 通过创建外部类的实例来访问外部类的非静态成员
OuterClass outer = new OuterClass();
System.out.println(outer.outerMember); // 输出:10
}
}

在这个示例中,StaticInnerClass是一个静态内部类,它不能直接访问外部类OuterClass的非静态成员outerMember,因此在innerMethod()方法中,如果尝试直接访问outerMember,会导致编译错误。但是,通过创建OuterClass的实例,我们可以访问外部类的非静态成员,比如在main()方法中,我们创建了一个OuterClass的实例outer,并且通过该实例访问了outerMember成员。

三、局部内部类(Local Inner Class):

  • 局部内部类定义在方法或作用域内部,只能在所在的方法或作用域内使用。
  • 结论:局部内部类能不能访问外部类的数据,取决于局部内部类所在的方法。
    • 如果这个方法是静态的:只能访问外部类中静态的。
    • 如果这个方法是实例的:可以都访问。
  • 局部内部类可以访问外部类的成员变量和方法,但只能访问 final 或 effectively final 的局部变量(只不过从JDK8开始。这个final关键字不需要提供了。系统自动提供。)。
  • 局部内部类不能使用访问权限修饰符修饰。
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
33
34
35
public class OuterClass {

// 静态变量
private static int k = 1;
// 实例变量
private int f = 2;

public void m1(){
// 局部变量
int i = 100;
// 局部内部类
class InnerClass {
// 实例方法
public void x(){
System.out.println(k);
System.out.println(f);
System.out.println(i);
}
}
// new对象,因为其生命周期所以只能在方法体中new对象。
InnerClass innerClass = new InnerClass();
innerClass.x();
}

public static void m2(){
int i = 100;
// 局部内部类
class InnerClass {
public void x(){
System.out.println(k);
//System.out.println(f);
}
}
}
}
1
2
3
4
5
6
7
public class OuterClassTest {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
outerClass.m1();
}
}

四、*匿名内部类(Anonymous Inner Class):

  • 匿名内部类是没有显式名称的内部类,通常用于实现接口或继承父类,并在创建对象时进行定义。
  • 匿名内部类不能定义构造方法,但可以初始化块和成员变量。
  • 匿名内部类可以访问外部类的成员变量和方法,以及方法内的 final 局部变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//EG1:
public class Outer {
public void methodWithInterface() {
// 使用匿名内部类实现接口
MyInterface myInterface = new MyInterface() {
@Override
public void interfaceMethod() {
System.out.println("Implementation of interface method");
}
};
myInterface.interfaceMethod();
}
}

interface MyInterface {
void interfaceMethod();
}
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//EG2:
public class Test {
public static void main(String[] args) {
// 创建电脑对象
Computer computer = new Computer();
//computer.conn(new Printer());

// 以下conn方法参数上的代码做了两件事:
// 第一:完成了匿名内部类的定义。
// 第二:同时实例化了一个匿名内部类的对象。
computer.conn(new Usb(){
// 接口的实现
@Override
public void read() {
System.out.println("read.....");
}

@Override
public void write() {
System.out.println("write.....");
}
});
}
}

class Computer {
public void conn(Usb usb){
usb.read();
usb.write();
}
}

interface Usb {
void read();
void write();
}

// 编写一个接口的实现类。若这个实现类可能只使用一次,这时可以使用匿名内部类避免类爆炸。
/*
class Printer implements Usb {

@Override
public void read() {
System.out.println("打印机开始读取数据");
}

@Override
public void write() {
System.out.println("打印机开始打印");
}
}
*/