Java 内部类

本文最后更新于:2024年3月18日 凌晨

Java 内部类

  • 内部类是指嵌套在一个类中的类,因此,有时也称为嵌套类(NestedClass),而包含内部类的那个类称为外层类(OuterClass),内部类与外层类存在逻辑上的所属关系,内部类的使用要依托外层类,这点与包的限制类似。
  • 内部类一般用来实现一些没有通用意义的功能逻辑,与类的其他成员一样,内部类也分带static修饰的静态内部类和不带static修饰的成员类。

成员内部类

  • 内部类与外层类的其他成员处于同级位置,所以也称为成员类,在外层类中的成员属性或方法定义中可创建内部类的对象,并通过对象引用访问内部类的成员,使用内部类有如下特点:
    • 内部类的定义可以使用访问控制符public,protected和private修饰。
    • 在内部类中可以访问外层类的成员,但如果外层类的成员与内部类的成员存在同名现象,则按最近优先原则处理。
    • 在内部类中,this指内部类的对象,要访问外层类的当前对象须加上外层类名作前缀,例如,以下内部类中用OuterOne.this表示访问外层类的this对象。

[例8-3]:内部类可访问外部类的成员。

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
public class OuterOne {
private int x = 3;
private int y = 4;

public void OuterMethod() {
InnerOne ino = new InnerOne();
ino.innerMethod();
}

public class InnerOne {// 内部类。
private int z = 5;
int x = 6;

public void innerMethod() {
System.out.println("y is" + y);
System.out.println("z is" + z);
System.out.println("x=" + x);
System.out.println("this.x=" + this.x);
System.out.println("OuterOne.this.x=" + OuterOne.this.x);
}
}// 内部类结束。

public static void main(String[] args) {
OuterOne my = new OuterOne();
my.OuterMethod();
}
}

y is4
z is5
x=6
this.x=6
OuterOne.this.x=3
  • 程序中所有定义的类均将产生相应的字节码文件,以上程序中的内部类经过编译后产生的字节码文件名为OuterOne$InnerOne.class,内部类的命名除了不能与自己的外层类同名外,不必担心与其他类名的冲突,因为其真实的名字加上了外层类名作为前缀。
  • 不能直接在main等静态方法中直接创建内部类的对象,在外界要创建内部类的对象必须先创建外层类对象,然后通过外层类对象去创建内部类对象,例如:
1
2
3
4
public static void main(String arg[]){
OuterOne.InnerOne i = new OuterOne().new InnerOne();
i.innerMethod();
}

静态内部类

  • 内部类可定义为静态的,静态内部类不需要通过外层类的对象来访问,静态内部类不能访问外层类的非静态成员。

[例8-4]:静态内部类举例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Outertwo {
private static int x = 3;

public static class Innertwo {// 静态内部类。
public static void m1() {// 静态方法。
System.out.println("x is" + x);
}

public void m2() {// 实例方法。
System.out.println("x is" + x);
}
}// 内部类结束。

public static void main(String[] args) {
Outertwo.Innertwo.m1();// 静态方法直接访问。
new Outertwo.Innertwo().m2();// 通过对象访问内部类的实例方法。
}
}
  • 程序在静态内部类Innertwo中定义了两个方法时,方法m1()为静态方法,在外部要调用该方法直接通过类名访问,例如:
1
Outertwo.Innertwo.m1();
  • 而方法m2()为实例方法,必须通过创建内部类的对象来访问,但是由于这里内部类是静态类,所以可以通过外层类名直接范文内部类的构造方法,例如:
1
new Outertwo.Innertwo().m2();

局部内部类与匿名内部类

局部内部类

  • 内部类也可以在某个方法中定义,这种内部类称为局部内部类(LocalClass),在方法内通过创建内部类的对象去访问其成员。
  • 由于内部类对象的创建与方法内定义的局部变量的赋值没有逻辑关系,所以,Java规定方法内定义的内部类只允许访问方法中定义的常量,注意,方法中的内部类要先定义后使用。

[例8-5]:方法中的内部类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class InOut{
public void amethod(final int x){
class Bicyle{
public void sayHello(){
System.out.println("hello!"+x);
}
}
new Bicyle().sayHello();;
}

public static void main(String[] args) {
new InOut().amethod(23);
}
}

hello!23

匿名内部类

  • Java允许创建对象的同时定义类的实现,但是未规定类名,Java将其定义为匿名内部类。
  • 匿名内部类可以继承其他类或实现其他接口,在Swing编程和Android开发中常用此方式来实现事件监听和回调。

[例8-6]:匿名内部类的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface sample {// 匿名内部类的使用。
void testMethod();
}

public class AnonymousInner {
void OuterMethod() {
new sample() { // 定义一个实现sample接口的匿名内部类。
public void testMethod() { // 实现接口定义的方法。
System.out.println("just test");
}
}.testMethod();// 调用内部类中定义的方法。
}

public static void main(String[] args) {
AnonymousInner my = new AnonymousInner();
my.OuterMethod();
}
}


just test
  • 上面程序中,由接口直接创建对象似乎是不可能的,但要注意后面跟着的大括号中给出了接口的具体实现,实际上这里的意思是创建一个实现sample接口的匿名内部类对象。
  • 注意:在程序编译时,匿名内部类同样会产生一个对应的字节码文件,其特点是以编号命名,例如,上面匿名内部类的字节码文件为AnonymousInner$1.class,如果有更多的匿名内部类将按递增序号命名。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!