概述

在Java中,可以将一个类定义在另一个类里面或者一个方法里边,这样的类称为内部类,广泛意义上的内部类一般包括四种:

  • 成员内部类

  • 局部内部类

  • 匿名内部类

  • 静态内部类

成员内部类

  • 该类像是外部类的一个成员,可以无条件的访问外部类的所有成员属性和成员方法(包括private成员和静态成员)

  • 成员内部类拥有与外部类同名的成员变量时,会发生隐藏现象,即默认情况下访问的是成员内部类中的成员。如果要访问外部类中的成员,需要以下形式访问:【外部类.this.成员变量 或 外部类.this.成员方法】;

  • 在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问;

  • 成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象;

  • 内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。如果成员内部类用private修饰,则只能在外部类的内部访问;如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。外部类只能被public和包访问两种权限修饰。

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
public class OuterClass {
private String str;
public static final String testStr = "琦玉";

public OuterClass(String str) {
this.str = str;
}

public String testArea() {
return str;
}

// 成员内部类(普通内部类)
class InnerClass {
// 1. 成员内部类不可以定义静态的属性和方法
//private static String str;
private String str;

public InnerClass(String str) {
this.str = str;
}

public String testArea() {
return str;
}

// 测试内部类中和外部类出现同名方法
private String test() {
// 在内部类中出现和外部类同名方法,默认调用本类中的方法
//testArea();
// 外部类名.this.方法名/类名 可以调用外部方法
// 无条件的访问外部类所有成员属性,和成员方法(即使是private,或者static)
System.out.println(OuterClass.this.str); // 外部类
System.out.println(testStr); // 琦玉
return OuterClass.this.testArea();
}
}

public static void main(String[] args) {
OuterClass outerClass = new OuterClass("外部类");
InnerClass innerClass = outerClass.new InnerClass("局部内部类");
System.out.println(outerClass.testArea()); // 打印 外部类
System.out.println(innerClass.test()); // 打印 外部类 通过(外部类名.this.方法名)可以调用外部方法调用了外部类中方法
System.out.println(innerClass.testArea()); // 打印 局部外部类
/**
* 输出结果:
* 外部类
* 外部类
* 琦玉
* 局部外部类
*/
}
}

局部内部类

  • 局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内;
  • 局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

这个局部内部类太鸡肋了,应该都不怎么使用,定义的时候和普通的class是一样的,除了不能用修饰符,还有作用域太小了吧,谁没事在代码块中定义一个局部内部类啊。

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 static void memberFunction() {
// 不可用修饰符修饰
class PartInnerClass {
private static final String str = "aaa";
private String str1 = "sss";

public PartInnerClass(String str1) {
this.str1 = str1;
}

public String test() {
return str1;
}
}
PartInnerClass innerClass = new PartInnerClass("局部内部类");
System.out.println(innerClass.test());
}

public static void main(String[] args) {
// 局部内部类出了作用域就无法使用了!!!
//new PartInnerClass("sss");
memberFunction();
/**
* 输出结果:
* 局部内部类
*/
}
}

匿名内部类

  • 一般使用匿名内部类的方法来编写事件监听代码;

  • 匿名内部类不能定义静态成员、方法和类;

  • 匿名内部类是不能有访问修饰符和static修饰符的;

  • 匿名内部类是唯一一种没有构造器的类;

  • 匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

因为匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。

实现方式

  • 继承一个类,重写其方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class OuterClass {
public static void main(String[] args) {
Thread thread = new Thread() {
private static final String str = "匿名内部类通过继承实现";
@Override
public void run() {
System.out.println(str);
}
};
thread.run();
/**
* 输出结果:
* 匿名内部类通过继承实现
*/
}
}
  • 实现一个接口(可以是多个),实现其方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class OuterClass {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
private static final String str = "匿名内部类通过接口实现";
@Override
public void run() {
System.out.println(str);
}
};
runnable.run();
/**
* 匿名内部类通过接口实现
*/
}
}

静态内部类

  • 静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似;

  • 不能使用外部类的非static成员变量或者方法。

静态内部类如果去掉关键字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
public class OuterClass {
private String str;

public static final String testStr = "琦玉";

public OuterClass(String str) {
this.str = str;
}

// 成员内部类(普通内部类)
private static class InnerClass {
private String str;

// 可以定义静态的参数
private static final String str1 = "静态内部类的静态参数";


public InnerClass(String str) {
this.str = str;
}

// 测试内部类中和外部类出现同名方法
private String test() {
// 只能访问外部类的静态成员变量,或者方法
System.out.println(testStr); // 琦玉
return str;
}
}

public static void main(String[] args) {
// 静态内部类不依赖外部类,直接声明就可以
InnerClass innerClass = new InnerClass("静态内部类");
System.out.println(innerClass.test()); // 打印 静态内部类
/**
* 输出结果:
* 琦玉
* 静态内部类
*/
}
}

理解

这些内部类根本不用记,从名字上就可以知道意思;

成员内部类:这个就想成类的成员变量,成员变量能被各种访问符修饰,这个自然可以,成员变量依赖类的实例化,这个也依赖于外部类啊。

静态内部类:了解了成员内部类,加一个static修饰就是静态内部类了啊,就相当于普通的成员变量,加一个static修饰不就变成,类变量了,类变量,类方法不依赖类的实例变量,只能调用类中静态方法和静态变量,那么这个静态内部类也不就一样,就不依赖于外部类,直接new,只能用外部类的静态方法和静态变量。

局部内部类:局部内部类这个更加见名知意了,局部的,在一个方法中,或者代码块中,仅仅在这个中生效,就想象成方法中定义的一个局部变量,怎么可能用修饰符修饰。

匿名内部类:这个也见名知意,就是没有名字的内部类,为什么没有名字,肯定是new xxx() {} 重写方法或者实现接口中的方法,这个用的比较多应该熟悉。

  • 成员内部类===》类的成员变量
  • 静态内部类===》类的类变量
  • 局部内部类===》方法的局部变量
  • 匿名内部类===》。。。。

实际上我感觉对普通的程序员来说这些内部类就偶尔用一用匿名内部类吧,看那jdk源码中发现用了很多成员内部类,和静态内部类。我反正没怎么用过,比较low,我对内部类的理解仅此而已,仅仅是知道些特性,到底该怎么用,何时去用还差一点感觉。