注:

非静态内部类和外部类有同名变量和方法时,需要通过Outer.this方式来访问外部类成员变量或方法。

成员内部类

定义在一个类的内部,外部类的每个对象都会加载一次,不可以定义静态成员和方法,可访问外部类的所有私有字段/方法,

对于私有字段,访问,编译器会生成一个access函数提供调用。

image-20201215210428834

image-20201215210440082

image-20201215210446377

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
76
77
78
79
80
81
/**
* @author CZM
* @create 2020/12/15
* 成员内部类
*/
public class InternalClass {
private String name = "默认名";
private static int age = 9;
private float field = 2.1f;
/**
也可用protected、private修饰内部类
*/
public class Internal {
private int age;
private String name = "内部类的默认name";

public Internal() {
}

public Internal(int age) {
this.age = age;
}

/**
* 打印外部与内部字段
*/
public void printOut() {
System.out.println(field);

//内部类也有重名字段时
//默认访问内部类字段
System.out.println("内部age:" + age); //内部age:0
System.out.println("内部name:" + name); //内部name:内部类的默认name
// 访问外部类
System.out.println("外部age:" + InternalClass.age); //外部age:9
System.out.println("外部name:" + InternalClass.this.name); //外部name:默认名
}

/**
* 返回外部实例
*
* @return
*/
private InternalClass getOutClass() {
return InternalClass.this;
}

@Override
public String toString() {
return "Internal{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}

public void print() {
Internal internal = new Internal();
//外部类可以访问,修改内部类private字段
internal.age = 2;
System.out.println(internal); //Internal{age=2, name='内部类的默认name'}
internal.name = "修改后的内部name";
System.out.println(internal.name); // 修改后的内部name


}

public static void main(String[] args) {
InternalClass internalClass = new InternalClass();
internalClass.print();

//实例化内部类前必须先实例化外部类
Internal internal = internalClass.new Internal();

internal.printOut();
System.out.println(internalClass == internal.getOutClass());

Class1 class1 = new Class1();
System.out.println(class1.age1);
}
}

局部内部类

定义载方法内部或作用域内,不能被public、private、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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

/**
* @author CZM
* @create 2020/12/15
*/
public class MethodClass {
private int outNUm = 1;
private int num2 = 2;
class InClass {

}
//定义在方法内
public void test1(){
//1.8之后java隐式的将x修饰为final
int test1Field = 111;
//局部内部类
class Method{
private int num1 = outNUm * 4;
private int num2 = 5;

//可直接访问成员内部类
InClass inClass = new InClass();
public void method1() {
System.out.println("局部内部类访问本地方法的变量:"+test1Field);
}
}
Method method = new Method();
System.out.println(method.num1);
System.out.println("外部num2"+MethodClass.this.num2);
System.out.println(method.num2);

method.method1();

}
//定义在作用域内
private void test2(){
if(true){
class Partial{
private String id;
private String getId(){
return id;
}
}
Partial ts = new Partial();
ts.id = "123";
System.out.println(ts.getId());
}
}


public static void main(String[] args) {
MethodClass methodClass = new MethodClass();
methodClass.test1();
methodClass.test2();
}
}

局部内部类访问局部变量,局部变量必须加final修饰。

因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,局部对象还要使用这个局部变量。为了让数据还能继续被使用,就用fian1修饰局部变量,这样,在堆内存里面存储的其实是一个常量值。

image-20201215213854116

匿名内部类

一个接口的实现类,或者是继承于某个父类的子类,我们只使用一次。就可以使用匿名内部类。匿名内部类使用方法的本地变量也是要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
package com.czm.classes;

import javafx.scene.Parent;

/**
* @author CZM
* @create 2020/12/15
*/
interface Parents {
void print(boolean flag);
}
class Persion{
public void work() {
System.out.println("work……");
}
}
public class AnonymousInnerClass {
private int num1 = 1;
Parents father = new Parents() {
@Override
public void print(boolean flag) {
System.out.println("匿名内部类:"+flag);
System.out.println("外部字段"+num1);
}
};
//lamber表达式
Parents mothor = (e)->{
System.out.println("lamber实例化的匿名内部类:"+e);
};



Persion persion = new Persion(){

@Override
public void work() {
System.out.println("重写父类方法");
super.work();
}
};

void test1() {
int tt = 12;
Persion p = new Persion(){
@Override
public void work() {
System.out.println("在方法中使用后匿名内部类");
System.out.println(tt);
super.work();
}
};
p.work();
}

public static void main(String[] args) {
AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass();
anonymousInnerClass.father.print(true);
anonymousInnerClass.mothor.print(true);
anonymousInnerClass.persion.work();
anonymousInnerClass.test1();

}
}

静态内部类

关键字static修饰,只能访问外部静态字段和方法,根成员内部类一样可以用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

/**
* @author CZM
* @create 2020/12/15
*/
public class StaticInnerClass {
static int num = 2;
public static class StaticClass{
int num1 = num;
static {
System.out.println("初始化静态内部类");
}
public static void print() {
System.out.println("静态内部方法");
}
protected void test() {
System.out.println("test");
}
}
/**
* 控制台打印如下:
*
* 初始化静态内部类
* 静态内部方法
* test
*/
public static void main(String[] args) {
StaticClass.print();
StaticClass staticClass = new StaticClass();
staticClass.test();
}
}

END