JAVA 内部类

    定义在一个类的内部的类叫内部类,包含内部类的类称为外部类。内部类可以声明publicprotectedprivatedefult等访问限制,也可以声明为abstract供其他内部类或外部类继承和扩展,也可以声明为staticfinal。本文主要是介绍成员内部类、静态内部类、局部内部类、匿名内部类以及成员内部类和静态内部类的区别。

成员内部类

    成员内部类相当于外部类的一个成员,成员内部类可以直接访问外部类的所有(包括私有)成员属性和方法;外部类访问内部类的成员属性和方法,需要通过内部类的实例来访问。需要注意:成员内部类不能存在任何static变量和方法,但 static final 的常量是可以的;原因:成员内部类是依赖于外部类的实例,而静态变量和方法不依赖对象的,在加载静态域时,外部类的实例还未创建,自然不行;但是常量在编译期就确定,放在常量池中。内部类中存在一个外部类的引用,可以用OuterClass.this来指代。如果外部类和内部类具有相同的成员变量和方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量或方法,需要显示指代,如OuterClass.this.attr/func()

静态内部类

    静态内部类和外部类的对象没有关联。可以将静态内部类看成一个普通类,只是被声明在另一个类的内部。如果静态内部类被声明为private,则该静态内部类只能在外部类中使用。静态内部类中不能直接访问外部类的非static成员变量和方法。创建静态内部类的对象时不需要通过外部类的对象来进行。

局部内部类

    局部内部类是嵌套在方法和作用域内,就像方法的一个局部变量。局部内部类是不能有publicprotectedprivate 以及 static 等修饰符的,因为它的作用域被局限在声明这个局部类的块中。局部内部类除了可以访问外部类的成员以外,还可以访问它所在的作用域中的被final修饰的局部变量。

匿名内部类

    匿名内部类是对局部内部类的深化。匿名内部类不能定义任何静态方法或属性;不能定义抽象的方法,且必须实现接口或抽象父类的所有抽象方法。匿名内部类只能访问外部类的静态成员方法或属性。如果内部类继承父类或实现接口,可以不用内部类创建对象,直接将所需要的功能转化为匿名内部类的方法。

成员内部类与静态内部类的区别

    1. 创建内部类对象的方式不同:静态内部类和普通静态类一样,直接new一个对象实例,如StaticInnerClass staticInnerObj = new StaticInnerClass();;成员内部类创建内部类对象需要先创建外部类对象,再通过外部类对象创建成员内部类的对象,如OutClassTest.InnerClass innerObj = new OutClassTest().new InnerClass();
    2. 调用内部类的方法或属性的方式不同:调用静态内部类的方法和属性只需要用静态内部类的类名即可,调用成员内部类的方法和属性必须通过内部类的对象来调用。
    3. 静态内部类只能访问外部类的静态方法或静态属性;成员内部类可以访问外部类的所有方法和属性。
    4. 静态内部类可以定义静态方法和属性,成员内部类不能定义静态方法和属性,但可以定义static 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public class OutClassTest {
private int outI;
private int i;
private static int outStaticJ;

public OutClassTest() {
i = 1;
outI = 1;
outStaticJ = 1;
}
public void outFunc() {
System.out.println("this is outFunction");
}
public static void outStaticFunc() {
System.out.println("this is outStaticFunction");
}
private class InnerClass {
private int innerI;
private int i;
// ① 非静态内部类不能定义静态成员(变量,方法)
//private static int innerStaticJ;
public InnerClass() {
innerI = 2;
i = 2;
}
public void transferOutCalss() {
// ② 非静态内部类可以访问外部类的所有成员(方法,属性)
System.out.println("InnerClass transfer OutClassTest.outI:" + outI);
System.out.println("InnerClass transfer OutClassTest.outStaticJ:" + outStaticJ);
System.out.println("InnerClass.i:" + i);
outFunc();
outStaticFunc();
// ③ 若内部类和外部类有相同的成员变量,通过显示的OutClassTest.this来调用。
System.out.println("InnerClass transfer OutClassTest.i :" + OutClassTest.this.i);
}

public void innerFunc() {
System.out.println("this is innerFunction");
}
}
private static class StaticInnerClass {
private int staticInnerI;
private static int staticInnerStaticJ;
public StaticInnerClass(){
staticInnerI = 3;
staticInnerStaticJ = 3;
}
public void transferOutCalss() {
// ④ 静态内部类不可用访问外部类的非静态成员(方法,属性)
// System.out.println("StaticInnerClass transfer OutClassTest.outI:" + outI);
// outFunc();
System.out.println("StaticInnerClass transfer OutClassTest.outStaticJ:" + outStaticJ);
outStaticFunc();
}
public void innerFunc() {
System.out.println("this is staticInnerFunction");
}
}
public static void main(String[] args) {
// 创建一个外部类的对象
OutClassTest outObj = new OutClassTest();
// 通过外部类的对象 new 一个非静态内部类
OutClassTest.InnerClass innerObj = outObj.new InnerClass();
// ⑤ 调用非静态内部类的方法和属性,需要通过外部类的对象创建内部类的实例
innerObj.innerFunc();
innerObj.transferOutCalss();
System.out.println("innerI:"+innerObj.innerI);
// ⑥ 创建静态内部类的对象不需要通过外部类的对象来创建,跟普通静态类一样
StaticInnerClass staticInnerObj = new StaticInnerClass();
// 静态内部类调用自身的成员变量或方法
staticInnerObj.transferOutCalss();
System.out.println("staticInnerI:"+staticInnerObj.staticInnerI);
System.out.println("staticInnerStaticJ:"+StaticInnerClass.staticInnerStaticJ);
}
}

总结

    1. 每个内部类都能独立的继承一个类,无论外部类是否已经继承了某个类。
    2. 内部类一般只为外部类使用,因此一般将内部类私有化(private)。

参考文章

java 内部类和静态内部类的区别
关于 Java 内部类的小抄