一、什么是内部类?
内部类是在一个类中的类,类的声明可在类中或方法中。
内部类的特点
优点:
- 内部类可以方便的访问外部类的隐式成员变量
- 一个类作为内部类是一种很好的信息隐藏,例如静态内部类需要使用 类名.内部类 引出,成员内部类使用 对象.内部类 引出
- 内部类可以实现单继承的局限性
缺点:
- 结构复杂
结构复杂体现下内部类的访问、内部类中使用外部类的成员变量等方面。
二、四种内部类
成员内部类
1public class Person {
2 String name;
3 int age;
4
5 public Person(String name, int age) {
6 this.name = name;
7 this.age = age;
8 }
9
10 public void broadcastRepeat(String msg) {
11 Beee b = new Beee(msg);
12 //开始哔哔
13 b.start();
14 }
15
16 // 复读机,重复Person想要说的信息
17 // 普通内部类通过外部类的对象创建, 引用属于对象,每个内部类对象都是不一样的
18 // 成员变量是static是必须使用final修饰
19 public class Beee extends Thread {
20 private String msg;
21
22 public Beee(String msg) {
23 this.msg = msg;
24 }
25
26 @Override
27 public void run() {
28 System.out.println(name);
29 while (true){
30 // 为什么能使用外部类的name,因为在调用构造器时把Person对象传入了进来,通过字节码可以看出来,下面对应着Beee的构造器
31 //INVOKESPECIAL elltor/basic/innerclass/normal/Person$Beee.<init> (Lelltor/basic/innerclass/normal/Person;Ljava/lang/String;)V
32 System.out.println(msg + " --" + name);
33 try {
34 Thread.sleep(1000);
35 } catch (InterruptedException e) {
36 e.printStackTrace();
37 }
38 }
39 }
40 }
41}
42
43
44// test
45public class T {
46 public static void main(String[] args) {
47 Person lisi = new Person("lisi", 18);
48 //lisi.broadcastRepeat("大家好哇~");
49
50 // 通过对象创建普通内部类,然后使用(看上去有些奇怪,因为这是对象持有的类,所以通过对象可以创建,而静态类使用类名.创建)
51 // 注意每个对象的内部类都是不一样的
52 Person.Beee bb = lisi.new Beee("bb create by lisi");
53 bb.start();
54 }
55
56}
静态内部类
1public class Person4 {
2 String name;
3 int age;
4
5 public Person4(String name, int age) {
6 this.name = name;
7 this.age = age;
8 }
9
10 public void broadcastRepeat(String msg) {
11 Beee b = new Beee(msg);
12 //开始哔哔
13 b.start();
14 }
15
16 // 静态内部类不能使用非静态的变量
17 // 静态内部内能够被其他类使用,而普通内部类只能在定义它类中使用
18 public static class Beee extends Thread {// 复读机,重复Person想要说的信息
19 private String msg;
20
21 public Beee(String msg) {
22 this.msg = msg;
23 }
24
25 @Override
26 public void run() {
27 while (true){
28
29 System.out.println(msg);
30 try {
31 Thread.sleep(1000);
32 } catch (InterruptedException e) {
33 e.printStackTrace();
34 }
35 }
36 }
37 }
38}
39
40
41//test
42public class T {
43 public static void main(String[] args) {
44 // 1
45 Person4 p = new Person4("lisi",19);
46 p.broadcastRepeat("hello everyone~ ");
47
48 // 2
49 Person4.Beee bee = new Person4.Beee("在Person4外使用");
50 bee.start();
51 }
52}
局部内部类
1public class Person2 {
2 String name;
3 int age;
4
5 public Person2(String name, int age) {
6 this.name = name;
7 this.age = age;
8 }
9
10 public void broadcastRepeat(String msg) {
11 // 不能使用publi或private修饰,可以使用final修饰
12 // 该类对于完结来说完全隐藏,每调用此方法创建一次且使用一次
13 class Beee extends Thread {// 复读机,重复Person想要说的信息
14 private String msg;
15
16 public Beee(String msg) {
17 this.msg = msg;
18 }
19
20 @Override
21 public void run() {
22 while (true){
23 System.out.println(msg);
24 try {
25 Thread.sleep(1000);
26 } catch (InterruptedException e) {
27 e.printStackTrace();
28 }
29 }
30 }
31 }
32
33 Beee b = new Beee(msg);
34 //开始哔哔
35 b.start();
36 }
37}
38
39// test
40public class T {
41 public static void main(String[] args) {
42 Person2 p = new Person2("lisi",18);
43 p.broadcastRepeat("大家好哇~");
44 }
45}
匿名内部类
1public class Person3 {
2 String name;
3 int age;
4
5 public Person3(String name, int age) {
6 this.name = name;
7 this.age = age;
8 }
9
10 // 匿名内部类1,匿名生成一个子类覆盖父类的方法
11 public void broadcastRepeat(String msg) {
12 new Thread() {
13 @Override
14 public void run() {
15 while (true) {
16 System.out.println(msg);
17 try {
18 Thread.sleep(1000);
19 } catch (InterruptedException e) {
20 e.printStackTrace();
21 }
22 }
23 }
24 }.start();
25 }
26
27 // 匿名内部类2,匿名创建接口对象
28 public void broadcastRepeat2(String msg) {
29
30 Runnable run = new Runnable() {
31 @Override
32 public void run() {
33 while (true) {
34 System.out.println(msg);
35 try {
36 Thread.sleep(1000);
37 } catch (InterruptedException e) {
38 e.printStackTrace();
39 }
40 }
41 }
42 };
43
44 new Thread(run).start();
45 }
46}
47
48
49// test
50public class T {
51 public static void main(String[] args) {
52 Person3 p = new Person3("lisi",18);
53 //p.broadcastRepeat("hello~");
54 p.broadcastRepeat2("hello2~");
55 }
56}
内部类的使用
在 JDK 的集合框架中大量使用到内部类
并不只有内部类,接口也可以定义在一个接口里。
Map 中定义的 Entry 接口
1public interface Map<K,V>{
2 interface Entry<K,V> {
3
4 K getKey();
5
6 V getValue();
7
8 V setValue(V value);
9
10 boolean equals(Object o);
11 }
12}
HashMap 中的内部类
构建者模式(Builder)
https://zhuanlan.zhihu.com/p/58093669
1public class Computer {
2 private final String cpu;//必须
3 private final String ram;//必须
4 private final int usbCount;//可选
5 private final String keyboard;//可选
6 private final String display;//可选
7
8 private Computer(Builder builder){
9 this.cpu=builder.cpu;
10 this.ram=builder.ram;
11 this.usbCount=builder.usbCount;
12 this.keyboard=builder.keyboard;
13 this.display=builder.display;
14 }
15 public static class Builder{
16 private String cpu;//必须
17 private String ram;//必须
18 private int usbCount;//可选
19 private String keyboard;//可选
20 private String display;//可选
21
22 public Builder(String cup,String ram){
23 this.cpu=cup;
24 this.ram=ram;
25 }
26
27 public Builder setUsbCount(int usbCount) {
28 this.usbCount = usbCount;
29 return this;
30 }
31 public Builder setKeyboard(String keyboard) {
32 this.keyboard = keyboard;
33 return this;
34 }
35 public Builder setDisplay(String display) {
36 this.display = display;
37 return this;
38 }
39 public Computer build(){
40 return new Computer(this);
41 }
42 }
43 //省略getter方法
44}