java学习笔记——基础11(final、static,内部类,包,代码块)

1、final 关键字
2、static 关键字
3、匿名对象
4、内部类
5、包的声明与访问
6、访问修饰符
7、代码块

01final关键字概念

* A: 概述
1
2
3
4
5
继承的出现提高了代码的复用性,并方便开发。但随之也有问题,有些类在描述完之后,不想被继承,
或者有些类中的部分方法功能是固定的,不想让子类重写。可是当子类继承了这些特殊类之后,
就可以对其中的方法进行重写,那怎么解决呢?
要解决上述的这些问题,需要使用到一个关键字finalfinal的意思为最终,不可变。
final是个修饰符,它可以用来修饰类,类的成员,以及局部变量。

02final修饰类义

* A: final 修饰类
1
2
3
4
5
		final修饰类"【不可以】【被继承】,但是【可以继承】其他类"
* B: 案例
class Yy {}
final class Fu extends Yy{} //可以继承Yy类
class Zi extends Fu{} //不能继承Fu类

03final修饰方法

* A: final修饰方法
1
2
3
4
5
6
7
8
9
10
11
final修饰的方法"不可以被覆盖","但如果父类中【没有】被final修饰方法,子类【覆盖】"后可以加final
* B: 案例
class Fu {
// final修饰的方法,不可以被覆盖,但可以继承使用
public final void method1(){}
public void method2(){}
}
class Zi extends Fu {
//重写method2方法
public final void method2(){}
}

04final修饰局部变量

* A:修饰基本数据类型变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
final修饰的变量称为常量,这些变量只能赋值一次


* B:案例1
final int i = 20;
i = 30; //赋值报错,final修饰的变量只能赋值一次

* C: 修饰引用数据类型
"【引用类型】的变量值为【对象地址值】,地址值【不能更改】,
但是【地址内的对象属性值可以修改】"

* D: 修饰引用数据类型
final Person p = new Person();
Person p2 = new Person();
p = p2; //final修饰的变量p,所记录的地址值不能改变
p.name = "小明";//可以更改p对象中name属性值
p不能为别的对象,而p对象中的name或age属性值可更改。

05final修饰成员变量

* A: 修饰成员变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 "修饰成员变量,需要在【创建对象】前赋值,否则报错。
(当没有显式赋值时,如有多个构造方法,则均需要为其赋值。)"

* B: 案例
class Demo {
//直接赋值
final int m = 100;

//final修饰的成员变量,需要在创建对象前赋值,否则报错。
final int n;
public Demo(){
//可以在创建对象时所调用的构造方法中,为变量n赋值
n = 2016;
}
}

06static的概念

* A:概念
1
2
3
4
当在定义类的时候,类中都会有相应的属性和方法。而属性和方法都是通过创建本类对象调用的。
"当在调用对象的某个方法时,但是这个方法【没有】访问到对象的【特有数据】时,方法创建这个对象有些多余。"
可是不创建对象,方法又调用不了,这时就会想,那么我们能不能不创建对象,就可以调用方法呢?
"可以的,我们可以通过static关键字来实现。static它是静态修饰符,一般用来修饰类中的成员。"

07static修饰的对象特有数据

* A:特点1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static "修饰的成员变量" "【属于类】""【不属于】这个类的某个对象"
(也就是说,多个对象在访问或修改static修饰的成员变量时,其中一个对象将static成员变量值进行了修改,
其他对象中的static成员变量值跟着改变,即"多个对象共享同一个" static 成员变量)
" 被静态修饰的成员,可以被 【类名】 【直接调用】"
"对象的【特有数据】: (非静态修饰)=> 【调用者只能是New 对象】
对象的【共享数据】: (静态修饰) => 【调用者是类名,也可以是New 对象(不建议这样用)】"


* B: 代码演示
class Demo {
public static int num = 100;
}

class Test {
public static void main(String[] args) {
Demo d1 = new Demo();
Demo d2 = new Demo();
d1.num = 200;
System.out.println(d1.num); //结果为200
System.out.println(d2.num); //结果为200
}
}

08static的内存图

方法调用的内存图

09static注意事项_【静态不能直接调用非静态】

* A: 注意事项    
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
static修饰的成员可以并且"建议通过类名直接访问"

* B: 访问静态成员的格式:
" 类名.静态成员变量名
类名.静态成员方法名(参数)
"
对象名.静态成员变量名 ------不建议使用该方式,会出现警告
对象名.静态成员方法名(参数) ------不建议使用该方式,会出现警告

* C: 代码演示
class Demo {
//静态成员变量
public static int num = 100;
//静态方法
public static void method(){
System.out.println("静态方法");
}
}
class Test {
public static void main(String[] args) {
System.out.println(Demo.num);
Demo.method();
}
}
————————————————————————————————————————————————————————————————————————————————————————
*"【静态内容】是优先于【对象】存在,【只能访问静态】""不能"使用this/super
"静态修饰的内容存于静态区"
class Demo {
//成员变量
public int num = 100;
//静态方法
public static void method(){
//this.num; 不能使用this/super。
System.out.println(this.num);
}
}
————————————————————————————————————————————————————————————————————————————————————————

*"同一个类中,静态成员【只能】访问静态成员"
class Demo {
//成员变量
public int num = 100;
//静态成员变量
public static int count = 200;
//静态方法
public static void method(){
//System.out.println(num); 静态方法中,只能访问静态成员变量或静态成员方法
System.out.println(count);
}
}
————————————————————————————————————————————————————————————————————————————————————————
*"【非静态内容】 【只能】 通过 创建【本类对象】,
再通过【 对象.成员变量 】 OR 【 对象.成员方法(参数) 】的方式调用"

class Demo {
//成员变量
public int num = 100;
//静态成员变量
public static int count = 200;

//非静态方法
public void function(){
System.out.println("这是非静态方法 function");
}
//静态方法
public static void method(){
//System.out.println(num);
// 静态方法中,只能访问静态成员变量或静态成员方法

System.out.println(count);
//【非静态内容】 【只能】 通过 创建【本类对象】,
// 再通过【 对象.成员变量 】 OR 【 对象.成员方法(参数) 】的方式调用
Demo d = new Demo();
System.out.println(d.num);
d.function();
}
}
————————————————————————————————————————————————————————————————————————————————————————
*"main方法为静态方法仅仅为程序执行入口,它【不属于任何一个对象】,可以定义在任意类中。"
————————————————————————————————————————————————————————————————————————————————————————
举例:
class Test{
public static void hello(){
System.out.println("hello");
}
}

public class TTTss {
public static void main(String[] args) {
Test tt = null;
tt.hello();
}
}

运行结果:
能编译通过,并能正常运行,打印:hello。

注意:
Test类中的方法 hello() 是静态static 的,因此,"hello()方法归类所有,与对象无关。
当实例化Test类的时候,【静态成员】会被【优先加载】而且【只加载一次】,
所以【不受】【实例化对象】 new Test();影响"
"只要是用到了Test类,都会加载静态 hello()方法。"
此外,在【其他类】的【静态方法】中也能调用public的静态hello()方法。
—————————————————————————————————————————————————————————
总结:
"静态方法【不受】实例化对象的影响",即使Test tt = null;
这是只要调用了Test类,就会加载静态方法,tt中包含了Test类的初始化数据。
此外,如果hello()是【非静态的方法】,那就会报NullPointerException异常。

10static静态的使用场景

* A: 使用场景
1
2
3
4
5
6
7
static可以修饰"【成员变量】""【成员方法】"
什么时候使用static修饰"成员变量"
static修饰成员的时候,"这个成员会被类的所有对象所共享。一般我们把【共性数据】定义为静态的变量。"
————————————————————————————————————————————————————————————————————————————————————————
什么时候使用static修饰"成员方法"
"静态的方法【只能】访问静态的成员"" 如果静态方法中引用到了静态的其他成员,那么这个方法需要声明为静态的方法。"
"方法中【没有】调用【非静态成员变量】,则将方法定义为【静态】"

11对象中的静态调用

* A: 对象的静态调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"在多态中,无论是【静态成员变量】 还是【非静态成员变量】,【都看父类】"
————————————————————————————————————————————————————————————————————————————————————————
" 在多态中,【非静态成员方法】【编译】【看父类】,【运行】【看子类】,【父类没有】则编译失败。"
————————————————————————————————————————————————————————————————————————————————————————
" 但多态中的【静态成员方法】,【编译看父类】,【运行仍然看父类】。因为【静态和对象没有关系】,属于【静态绑定】。"
————————————————————————————————————————————————————————————————————————————————————————
即:"【只有】【非静态成员方法】 运行看 【子类】,其他看父类"
————————————————————————————————————————————————————————————————————————————————————————
* B: 举例
public class Test{
public static void main(String[] args){
Fu f = new Zi();
f.show(); //父类的引用和父类的方法绑定,和对象无关,不会在运行时动态的执行子类特有的方法。
}
}

12定义静态常量

* A: 静态常量
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
开发中,我们想在类中定义一个静态常量,通常使用public static final修饰的变量来完成定义。
"此时变量名用【全部大写】,多个单词使用下划线连接。"
* B: 定义格式:
public static final 数据类型 变量名 = 值;

* C: 如下演示:
class Company {
public static final String COMPANY_NAME = "传智播客";
public static void method(){
System.out.println("一个静态方法");
}
}

"当我们想使用类的静态成员时,【不需要创建对象】,【直接使用类名】来访问即可。"
System.out.println(Company.COMPANY_NAME); //打印传智播客
Company.method(); // 调用一个静态方法

* D: 注意:
"接口中的每个【成员变量】都默认使用" public static final修饰。
"所有【接口】中的【成员变量】【必须是静态常量】,由于【接口】【没有】【构造方法】,
所以【必须显示赋值】。可以【直接】用【接口名】访问"
interface Inter {
public static final int COUNT = 100;
}
" 访问接口中的静态变量 ":
Inter.COUNT
}

13匿名对象

* A:匿名对象的概述
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
* 匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量。
* B:案例
public class Person{
public void eat(){
System.out.println();
}
}

创建一个普通对象
Person p = new Person();
"创建一个匿名对象"
new Person();

* C: 匿名对象的特点
a:"创建匿名对象【直接使用】,【没有变量名】"
new Person().eat() //"eat方法被一个没有名字的Person对象调用了"。

b:"【匿名对象】在【没有指定】其【引用变量】时,【只能】【使用一次】,第二次使用则【重新】创建了【新的匿名对象】"
new Person().eat(); 创建一个匿名对象,调用eat方法
new Person().eat(); 想再次调用eat方法,重新创建了一个匿名对象

c:"【匿名对象】可以作为【方法接收的参数】、【方法返回值】使用"
class Demo {
public static Person getPerson(){
//普通方式
//Person p = new Person();
//return p;

//匿名对象作为方法返回值
return new Person();
}

public static void method(Person p){}
}

class Test {
public static void main(String[] args) {
//调用getPerson方法,得到一个Person对象
Person person = Demo.getPerson();

//调用method方法
Demo.method(person);
//匿名对象作为方法接收的参数
Demo.method(new Person());
}
}

14内部类及其特点

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
" 将类写在其他类的【内部】,可以写在其他类的【成员位置】和【局部位置】,这时写在其他类内部的类就称为【内部类】。
其他类也称为外部类 "
* B: 什么时候使用内部类
在描述事物时,若一个事物内部还包含其他可能包含的事物,比如在描述汽车时,汽车中还包含这发动机,
这时发动机就可以使用内部类来描述。
class 汽车 { //外部类
class 发动机 { //内部类
}
}
* C: 内部类的分类
注意:
(1) "外部类 修饰符 【只能】使用 public 和 【省略访问控制符】"
——————————————————————————————————————————————
"内部类 修饰符 可以使用:public protected private static 和 【省略访问控制符】"
解释:
外部类的上一级程序单元是包,所以它只有2个作用域:"同一个包内和任何位置"
因此只需2种访问权限:"包访问权限和公开访问权限",正好对应"省略访问控制符和public访问控制符"
省略访问控制符是包访问权限,即同一包中的其他类可以访问省略访问控制符的成员。
因此,如果一个外部类不使用任何访问控制符修饰,则只能被同一个包中其他类访问。

而内部类的上一级程序单元是外部类,
它就具有4个作用域:同一个类、同一个包、父子类和任何位置,因此可以使用4种访问控制权限
————————————————————————————————————————————————————————————————————————————————————————
(2) "【非静态成员内部类】【不能】拥有【静态成员变量】"

根据静态成员不能直接访非静态成员的规则,
"外部类的【静态方法】、静态代码块【不能直接】访问【非静态内部类】,
包括不能直接使用非静态内部类定义变量、创建实例等。"
总之,【不允许】在外部类的【静态成员】中直接使用【非静
态内部类】
但是:静态常量的【这里要注意静态常量一定拥有一个编译期常量的】
如: private static final double PI=3.14;

分析:
首先要明白以下三点:
1static类型的属性和方法,"在类加载的时候就会存在于内存中"
2、要想使用某个类的static属性和方法,那么"这个类必须要加载到虚拟机中"
3"非静态内部类【并不随】外部类一起加载""只有在【实例化外部类之后】才会加载"

现在考虑这个情况:"在外部类并没有实例化,内部类还没有加载,这时候如果调用内部类的静态成员或方法,
内部类还没有加载,却试图在内存中创建该内部类的静态成员,这明显是矛盾的。"
所以非静态内部类不能有静态成员变量或静态方法。

public class Outer {
private static int t1;
private int r1;

public class Inner{
private static int t1;//error
private static final double PI=3.14;
public void func(){
int e = r1;
e=t1;
e=new Outer().r1;;
e=Outer.t1;

}
}
}
——————————————————————————————————————————————
《 非静态方法可以调用静态成员方法和静态成员变量 》

————————————————————————————————————————————————————————————————————————————————————————
"内部类分为【成员内部类】与【局部内部类】"
————————————————————————————————————————————————————————————————————————————————————————
"我们【定义】【内部类】时,就是一个【正常定义类】的过程,
【同样】【包含】各种【修饰符】、【继承】与【实现关系】等"
————————————————————————————————————————————————————————————————————————————————————————
"在【内部类】中可以【直接】访问【外部类】的【所有成员】"

小结

1.为什么使用内部类?

使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响
1.1.使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:
(1)、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
(2)、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
(3)、创建内部类对象的时刻并不依赖于外围类对象的创建
(4)、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
(5)、内部类提供了更好的封装,除了该外围类,其他类都不能访问
2.内部类分类:

(一).成员内部类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Outer{
private int age = 99;
String name = "Coco";
public class Inner{
String name = "Jayden";
public void show(){
System.out.println(Outer.this.name);
System.out.println(name);
System.out.println(age);
}
}
public Inner getInnerClass(){
return new Inner();
}
public static void main(String[] args){
Outer o = new Outer();
Inner in = o.new Inner();
in.show();
}
}

1.Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,
如 public 、 protected 、 private 等
2.Inner 类中定义的 show() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,
如直接访问 Outer 类中的私有属性age

3.定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,
即:内部类 对象名 = 外部类对象.new 内部类( );
4.编译上面的程序后,会发现产生了两个 .class 文件: Outer.class,Outer$Inner.class{}
5.非静态成员内部类中不能存在任何 static 的变量和方法,可以定义常量:
(1).因为非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关,
简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过;
非静态内部类的作用域是实例级别

(2).常量是在编译器就确定的,放到所谓的常量池了
★★友情提示:
1.外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;
2.如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,
可以使用 this 关键字,如:Outer.this.name

(二).静态内部类: 是 static 修饰的内部类,

1.静态内部类不能直接访问外部类的非静态成员但可以通过 new 外部类().成员 的方式访问
2.如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;
如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员
3.创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名 = new 内部类();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Outer{
private int age = 99;
static String name = "Coco";
public static class Inner{
String name = "Jayden";
public void show(){
System.out.println(Outer.name);
System.out.println(name);
}
}
public static void main(String[] args){
Inner i = new Inner();
i.show();
}
}
(三).局部内部类:其作用域仅限于方法内,方法外部无法访问该内部类

(1).局部内部类就像是方法里面的一个局部变量一样是不能有 public、protected、private 以及 static 修饰符的
(2).只能访问方法中定义的 final 类型的局部变量,因为:
当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在,
直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量;

==>使用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
/*
使用的形参为何要为 final???
在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,
也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,
毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解
和不可接受的,所以为了保持参数的一致性,就规定使用 final 来避免形参的不改变
*/
public class Outer{
public void Show(){
final int a = 25;
int b = 13;
class Inner{
int c = 2;
public void print(){
System.out.println("访问外部类:" + a);
System.out.println("访问内部类:" + c);
}
}
Inner i = new Inner();
i.print();
}
public static void main(String[] args){
Outer o = new Outer();
o.show();
}
}

.

(3).注意:在JDK8版本之中,方法内部类中调用方法中的局部变量,可以不需要修饰为 final,匿名内部类也是一样的,主要是JDK8之后增加了 Effectively final 功能
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
反编译jdk8编译之后的class文件,发现内部类引用外部的局部变量都是 final 修饰的

(四).匿名内部类:

(1).匿名内部类是直接使用 new 来生成一个对象的引用;
(2).对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,
该类的定义会立即消失,所以匿名内部类是不能够被重复使用;
(3).使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口;
(4).匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法;
(5).匿名内部类中不能存在任何的静态成员变量和静态方法,匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法
(6).匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
}; /* 注意:分号不能省 */
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chenssy");
System.out.println(inner.getNumber());
}
}
interface InnerClass {
int getNumber();
}

15成员内部类的调用格式

* A: 格式
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

"【成员内部类】,定义在【外部类】中的【成员位置】。与类中的成员变量【相似】,可通过【外部类】【对象】进行访问"
* B: 定义格式
class 外部类 {
修饰符 class 内部类 {
//其他代码
}
}

* C: 访问方式
————————————————————————————————————————————————————————————————————————————————————————
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();

Outer.this.成员 >>> "表示内部类对外部类的成员引用"
this.成员 >>> "表示内部类对自己成员的调用"
————————————————————————————————————————————————————————————————————————————————————————
注:其他类调用内部类的成员:
(一)访问"【非静态成员内部类】"
"——————————————————————————————————————————————————————————"
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
"——————————————————————————————————————————————————————————"
***************************************************************************************
**********"【非静态内部类】【不能】 定义【 静态方法、静态成员变量、静态初始化块】"**********
***************************************************************************************
"需要在外部类中创建 内部类对象 ==>>>调用方法"

根据静态成员不能直接访非静态成员的规则,
"外部类的【静态方法】、静态代码块【不能直接】访问【非静态内部类】,
包括不能直接使用非静态内部类定义变量、创建实例等。"
总之,【不允许】在中直接使用【非静
态内部类】
举例:
public class Outer_0 {
//非静态内部类
public class Inner_0{
}

//外部类的【静态方法】
public static void static_method(){
new Inner_0();//error,不允许在外部类的【静态成员】中【直接使用】非静态静内部类

"正确调用方式"
new Outer_0().new Inner_0();
}
}

访问"【非静态成员内部类】"
1)在【外部类】的"【非静态方法】"中访问:
"【new 内部类名()" OR "【 new 外部类名().new 内部类名() 】"

2)在【外部类以外】的"【非静态方法】"中访问:
"【只能】【 new 外部类名().new 内部类名() 】"

3)在【外部类】及 【外部类以外】的"【静态方法】"中访问:
" 【只能】通过【 new 外部类名().new 内部类名() 】" 方式访问




————————————————————————————————————————————————————————————————————————————————————————

(二)访问"【静态成员内部类】"
"——————————————————————————————————————————————————————————"
1)在【外部类】中使用静态内部类
new 静态内部类名();

调用静态内部类的"【非静态方法】"
new 外部类名.静态内部类名()

调用静态内部类的"【静态方法】"
静态内部类名.静态方法名();

2)在【外部类以外】使用静态内部类
因为【静态内部类】是外部类"类相关"的,"因此创建静态内部类对象时【无须】创建外部类对象"
在【外部类以外】的地方创建静态内部类实例的语法:
"***************************************************************************************"
外部类名.内部类名 变量名 = new 外部类名.静态内部类名();
"***************************************************************************************"
A:【调用非静态方法】: 变量名.静态方法名() OR new 外部类名.静态内部类名().静态方法名()

"——————————————————————————————————————————————————————————"
B:【调用静态方法】:
"在【外部类以外】:访问方式无需创建对象,利用 【 外部类名.静态内部类名.内部类静态方法 】访问内部类【静态方法】"
————————————————————————————————————————————————————————————————————————————————————————
* D: 成员内部类代码演示
class Body {//外部类,身体
private boolean life= true; //生命状态
public class Heart { //内部类,心脏
public void jump() {
System.out.println("心脏噗通噗通的跳")
System.out.println("生命状态" + life); //访问外部类成员变量
}
}
}

访问内部类
public static void main(String[] args) {
//创建内部类对象
Body.Heart bh = new Body().new Heart();
//调用内部类中的方法
bh.jump();
}


*F
public class Outer {
private int num;

public Outer(int num){
this.num = num;
}

public void ff() {
// 【静态内部类】 也可以创建对象
// 对内部类的方法进行调用
new LLei_static().hanshu();

}

//非静态成员内部类
public class Inner{
private int num =93;
public void func(){
int num=18;
System.out.println("成员内部类 Inner 的方法 func >> num: "+ num);//18,就近原则
System.out.println("成员内部类 Inner 的方法 func >> this.num: "+ this.num);//视为 访问 内部类对象(this)的成员变量,用this
System.out.println("成员内部类 Inner 的方法 func >> Outer.this.num: "+ Outer.this.num);//视为 访问 外部类对象(Outer.this)的成员变量,用Outer.this
}
}

//静态成员内部类
public static class LLei_static{
public void hanshu(){
int num=232;
System.out.println("成员内部类 LLei_static 的方法 hanshu >> num: "+ new Outer(89565).num);
}
}

}

public class TSET {
public static void main(String[] args) {
Outer.Inner in1 = new Outer(274).new Inner();
in1.func();

System.out.println("————————————————————————————————————1:");
Outer out =new Outer(2365);
Outer.Inner in2 = out.new Inner();
in2.func();

Outer static_out =new Outer(4345);
System.out.println("————————————————————————————————————2:");
//此时 将【静态成员内部类】理解为 一个成员变量
Outer.LLei_static static_in = new Outer.LLei_static();
static_in.hanshu();
}
}

16成员内部类的同名变量调用

* A: 代码实现
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
当在"【非静态内部类】""方法内"访问某个变量时,
(1)系统优先在该"方法内"查找是否存在该名字的"局部变量",如果存在就使用该变量;
"方法内""局部变量":直接用变量名 调用

(2)如果不存在,则到该方法所在的"内部类"中查找是否存在该名字的成员变量,如果存在则使用该"成员变量";
"内部类"中的"成员变量"this.成员变量名 调用

(3)如果不存在,则到该内部类所在的"外部类"中查找是否存在该名字的"成员变量",如果存在则使用该成员变量;
"外部类"中的"成员变量":外部类名.this.成员变量名 调用

如果依然不存在,系统将出现编译错误:提示找不到该变量。
public class Outer {
int num = 1;
class Inner {
int num = 2;
public void inner(){
int num = 3;

//18,就近原则
System.out.println("成员内部类 Inner 的方法 func >> num: "+ num);

//视为 访问 内部类对象(this)的成员变量,用this
System.out.println("成员内部类 Inner 的方法 func >> this.num: "+ this.num);

//视为 访问 外部类对象(Outer.this)的成员变量,用Outer.this
System.out.println("成员内部类 Inner 的方法 func >> Outer.this.num: "+ Outer.this.num);
}
}
}

17 局部内部类

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
82
83
84
85
86
87

* A "局部内部类",定义在"【外部类方法】"中的"局部位置""与访问方法中的【局部变量】【相似】,
* 可通过【调用方法】【进行访问】".
* 局部类 "【不能】"publicprivate "修饰符进行声明,它的作用域被限定在所声明的【局部类的块】中。"
* B 定义格式

class 【外部类】 {
修饰符 返回值类型 【方法名(参数)】 {
class 【内部类】 {
//其他代码
}
}
}

* C 访问方式
"在【外部类方法】中,创建【内部类】【对象】,进行访问"

* D 局部内部类代码演示
定义类
class Party {//外部类,聚会
public void puffBall(){// 吹气球方法
class Ball {// 内部类,气球
public void puff(){
System.out.println("气球膨胀了");
}
}
//创建内部类对象,调用puff方法
new Ball().puff();
}
}
访问内部类
public static void main(String[] args) {
//创建外部类对象
Party p = new Party();
//调用外部类中的puffBall方法
p.puffBall();
}




————————————————————————————————————————————————————————————————————————————————————————
举例:
//局部内部类
public class Outer {
private int num =380;
public void method(){
final int TYU =56;
System.out.println("外部类 Outer 的方法");
}

public int outer_func( String s){
int num = 200; // num是局部变量
int yu=90;
int [] arr = new int[1];
//局部内部类
class Inner{
int num =567;
//如何调用 局部内部类 中的 方法?
public void inner_func(){
int num = 45456;
// s = "dvd";
// yu =56;
// yu++; //ERROR
arr[0]++;
arr[0]++;//通过引用数据类型,实现【局部内部类】中的 计数器
this.num++;// 该this指向【局部内部类 Inner 】【对象】的【成员属性】:567+1=568
System.out.println("局部内部类 Inner 的方法: " + this.num+ " "+ yu + s);
System.out.println("局部内部类 Inner 的方法:调用局部变量 " + arr[0]);
Outer.this.method();
}
public int inner_return(){
return this.num;//568
}
}


// 需要在【外部类】的【方法】中,创建【内部类】【对象】,进行访问
Inner in = new Inner();
in.inner_func();
System.out.println("this.num "+ this.num);// 该this指向 【外部类 Outer】【对象】的【成员属性】:380
return in.inner_return() + this.num + num;// num是局部变量:200



}
}

18匿名内部类

* A: 概述
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

内部类是为了应对更为复杂的类间关系。查看源代码中会涉及到,而在日常业务中很难遇到,这里不做赘述。
最常用到的内部类就是匿名内部类,它是局部内部类的一种。
定义的【匿名内部类】有两个含义:
"临时定义某一指定类型的子类"
"定义后【即刻】创建刚刚定义的这个【子类】的【对象】"

* B: 本质
"【匿名内部类】的【本质】是一个实现了【接口】或继承了某个【父类】的【子类匿名对象】".

1  匿名内部类"不能有构造方法"

2  匿名内部类"不能定义任何静态成员、方法和类"

3  匿名内部类"不能"public,protected,private,static

4  "只能"创建匿名内部类的"一个实例"

5 一个匿名内部类"一定是在new的后面",用其隐含实现一个接口或实现一个类。

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

public class test {
public static void main(String[] args) {
////使用匿名内部类
new Drink(){
public Drink(){"//error "不能有构造方法""

}

private int er;
private static int rt;"//error "不能定义任何静态成员、方法和类""

public void func(){
System.out.println("这是一个匿名内部类的 方法 func");
}
};


System.out.println("————————————————————————————————————2:");

new Drink(){
public void func(){
System.out.println("这是一个匿名内部类的 方法 func");
}
}.func();


System.out.println("————————————————————————————————————3:");
//创建匿名内部类 对象 dd
Drink dd = new Drink(){
public void func(){
System.out.println("这是一个匿名内部类的 方法 func");
}
};
//再通过 对象 调用 匿名内部类 的 func 方法
dd.func();

}
}

* C: 案例
public interface Smoking {
public abstract void smoking();
}
/*【回顾之前采用的方式】
* 实现类,实现接口 重写接口抽象方法,创建实现类对象
* class XXX implements Smoking{
* public void smoking(){
*
* }
* }
* XXX x = new XXX();
* x.smoking();
* Smoking s = new XXX();
* s.smoking();
*
* 匿名内部类,简化问题: 定义实现类,重写方法,建立实现类对象,合为一步完成
*/

测试类:
public class Test {
public static void main(String[] args) {
"//使用匿名内部类
/*
* 定义实现类,重写方法,创建实现类对象,一步搞定
* 格式:"
——————————————————————————————————————————————————————
new 接口或者父类(){
重写抽象方法
};
——————————————————————————————————————————————————————
"* 从 new开始,到分号结束
* 创建了接口的实现类的对象
*/"
new Smoking(){
public void smoking(){
System.out.println("人在吸烟");
}
}.smoking();
}
}

19匿名内部类_2

* A: 匿名内部类案例演示
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

public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}

测试代码
/*
* new Animal(){
public void eat(){
System.out.println("在吃饭");
}
public void sleep(){
System.out.println("在睡觉");
}
};
*/
"以上代码,就是Animal的子类的对象
利用多态性, 父类引用 = 子类的对象"


public class Test2 {
public static void main(String[] args) {
Animal a= new Animal(){
public void eat(){
System.out.println("在吃饭");
}
public void sleep(){
System.out.println("在睡觉");
}
};
a.eat();
a.sleep();
}
}

20包的概念

* A: 概念
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
java的包,其实就是我们电脑系统中的文件夹,包里存放的是"类文件(.java 或者 .class 文件)"
当类文件很多的时候,通常我们会采用多个包进行存放管理他们,这种方式称为"分包管理"
在项目中,我们将相同功能的类放到一个包中,方便管理。并且日常项目的分工也是"以包作为边界"
"类中声明的包必须与实际class文件所在的文件夹情况【相一致】,即类声明在a包下,
则生成的.class文件必须在a文件夹下,否则,程序运行时会找不到类"
"————————————————————————————————————————————————————————————————————————————————————————"

* B 声明格式
通常使用公司网址反写,"可以有【多层包】,包名采用【全部小写字母】,【多层包】之间用【”.”】连接"
类中包的声明格式:
——————————————————————————————
package 包名.包名.包名…;
——————————————————————————————
如:网址itheima.com那么网址反写就为com.itheima
itcast.cn 那么网址反写就为 cn.itcast
"注意:声明包的语句,必须写在程序【有效代码】的【第一行】(注释不算)"
代码演示:
package cn.itcast; //包的声明,必须在有效代码的第一行

import java.util.Scanner;
import java.util.Random;

public class Demo {}
"————————————————————————————————————————————————————————————————————————————————————————"

* C: 包的访问
在访问类时,为了能够找到该类,"必须使用含有包名的【类全名】(包名.类名)"
即:"包名.包名….类名"
如: java.util.Scanner
java.util.Random
cn.itcast.Demo
——————————————————————————————————————————————————————————
带有包的类,创建对象格式:包名.类名 变量名 = new 包名.类名();
——————————————————————————————————————————————————————————
如: cn.itcast.Demo d = new cn.itcast.Demo();
前提:包的访问与访问权限密切相关,这里以一般情况来说,即类用public修饰的情况。

"————————————————————————————————————————————————————————————————————————————————————————"

*D:类的简化访问
——————————————————————————————————————————————————————————
当我们要使用一个类时,这个类与当前程序在"同一个包中(即同一个文件夹中)"
或者"这个类是【java.lang】包中的类"时通常"【可以省略】掉【包名】",直接使用该类。
——————————————————————————————————————————————————————————
如:cn.itcast包中有两个类,PersonTest类,与Person类。
我们在PersonTest类中,访问Person类时,由于是同一个包下,访问时可以省略包名,即直接通过类名访问 Person。
——————————————————————————————————————————————————————————
类名 变量名 = new类名();
Person p = new Person();

当我们要使用的类,与当前程序"【不在】同一个包中(即【不同】文件夹中)"
要访问的类"必须"public"修饰才可访问"
package cn.itcst02;
public class Person {}

22导入包

* A:导入包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我们每次使用类时,都需要写很长的包名。很麻烦,我们可以通过import导包的方式来简化。
可以通过导包的方式使用该类,可以避免使用全类名编写(即,包类.类名)。
导包的格式:
import 包名.类名;

当程序导入指定的包后,使用类时,就可以简化了。演示如下
//导入包前的方式
//创建对象
java.util.Random r1 = new java.util.Random();
java.util.Random r2 = new java.util.Random();
java.util.Scanner sc1 = new java.util.Scanner(System.in);
java.util.Scanner sc2 = new java.util.Scanner(System.in);

//导入包后的方式
import java.util.Random;
import java.util.Scanner;
//创建对象
Random r1 = new Random();
Random r2 = new Random();
Scanner sc1 = new Scanner(System.in);
Scanner sc2 = new Scanner(System.in);
import导包代码书写的位置:在声明包package后,定义所有类class前,使用导包import包名.包名.类名;

23权限修饰符

* A 权限修饰符有哪些
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
 在Java中提供了四种访问权限,使用不同的访问权限时,被修饰的内容会有不同的访问权限,
以下表来说明不同权限的访问能力:

public protected default private
————————————————————————————————————————————————————————————————————————————————————————
"同一【类】中" √ √ √ √
————————————————————————————————————————————————————————————————————————————————————————
"同一包中(子类与无关类)" √ √ √
————————————————————————————————————————————————————————————————————————————————————————
"不同包的子类" √ √
————————————————————————————————————————————————————————————————————————————————————————
"不同包中的无关类"
————————————————————————————————————————————————————————————————————————————————————————

* B: 小结
归纳一下:在日常开发过程中,编写的类、方法、成员变量的访问
————————————————————————————————————————————————————————————————————————————————————————
private:要想"【仅能在本类中】"访问使用private修饰;
————————————————————————————————————————————————————————————————————————————————————————
default:要想"【本包】"中的类都可以访问"【不加修饰符】"即可;
————————————————————————————————————————————————————————————————————————————————————————
protected:要想"【本包】中的类与【其他包中的【子类】】"可以访问使用protected修饰
注意:
protected 修饰符 在"【跨包】调用成员"时:
"【只能】在 【子类的内部】【进行调用】:{ 直接用 【成员名】 OR 【super.成员名】 调用}
并且【不能】在【子类中】 通过 【创建对象】 【进行调用】"
————————————————————————————————————————————————————————————————————————————————————————
public:要想"【所有包】中的【所有类】"都可以访问使用public修饰。
————————————————————————————————————————————————————————————————————————————————————————
注意:如果类用public修饰,"则【类名】必须与【文件名】相同""一个文件中【只能】有一个" public修饰的类。
————————————————————————————————————————————————————————————————————————————————————————

24代码块

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
82
83
84
85
86
87
88
* A: 概述:
程序中用"【大括号括起来】"的代码叫"代码块"
————————————————————————————————————————————————————————————————————————————————————————

* B: 分类
"局部代码块" "构造代码块" "静态代码块" "同步代码块"

————————————————————————————————————————————————————————————————————————————————————————

* C "局部代码块":
"【局部代码块】是定义在【方法】或【语句】中"
特点:
"以”{}”划定的代码区域,此时只需要关注【作用域】的不同即可"
"【方法】和【类】都是以【代码块】的方式【划定边界】的"

————————————————————————————————————————————————————————————————————————————————————————
class Demo{
public static void main(String[] args) {
//局部代码块
{
int x = 1;
System.out.println("局部代码块" + x);
}
//局部变量作用域
int x = 99;
System.out.println("代码块之外" + x);
}
}
结果:
普通代码块1
代码块之外99
"【局部代码块】作用:可以【限定变量】的【声明周期】".

————————————————————————————————————————————————————————————————————————————————————————

* D: "构造代码块"
"【构造代码块】是定义在【类】中【成员位置】的代码块"
特点:
"【优先于】【构造方法】执行,构造代码块用于执行【所有对象】【均需要】的【初始化动作】"
"每【创建一个】对象均会【执行一次】构造代码块"
public class Person {
private String name;
private int age;

//构造代码块
{
System.out.println("构造代码块执行了");
}

Person(){
System.out.println("Person无参数的构造函数执行");
}
Person(int age){
this.age = age;
System.out.println("Person(age)参数的构造函数执行");
}
}
class PersonDemo{
public static void main(String[] args) {
Person p = new Person();
Person p1 = new Person(23);
}
}
结果:
构造代码块执行了
Person无参数的构造函数执行
构造代码块执行了
Person(age)参数的构造函数执行
————————————————————————————————————————————————————————————————————————————————————————

* E: "静态代码块"
"【静态代码块】是定义在【成员位置】",使用static "修饰的代码块"
特点:
"它【优先于】【主方法】执行、【优先于】【构造代码块】执行,
当以任意形式【第一次使用到该类】时执行"
"【该类】【不管创建多少对象】,【静态代码块】【只执行一次】"
"可用于给【静态变量赋值】,用来给【类进行初始化】"
public class Person {
private String name;
private int age;
//静态代码块
static{
System.out.println("静态代码块执行了");
}
}

————————————————————————————————————————————————————————————————————————————————————————
* F: "同步代码块"(多线程学习)
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
————————————————————————————————————————————————————————————————————————————————————————
举例:

class Person {
public Person(){
System.out.println("Class Person 构造方法");
}

{
System.out.println("Class Person 构造代码块 ");
}

static {
System.out.println("Class Person 【静态】代码块 ");
}

}

class Student extends Person {
public Student() {
System.out.println(" Student 构造方法");
}

static {
System.out.println(" Student 【静态】代码块");
}

{
System.out.println(" Student 构造代码块");
}

}

public class Test {
public static void main(String[] args) {
new Student();
System.out.println("————————————————————————————");
new Student();
}
}

————————————————————————————————————————————————————————————————————————————————————————
运行结果:

Class Person 【静态】代码块
Student 【静态】代码块
Class Person 构造代码块
Class Person 构造方法
Student 构造代码块
Student 构造方法
————————————————————————————
Class Person 构造代码块
Class Person 构造方法
Student 构造代码块
Student 构造方法
———————————————————————————————————————————————————————————————————————————————————————
结论:
"
【静态代码块】【只执行一次】
执行顺序:
* 静态代码块 > 构造代码块(初始化块) > 构造方法(构造器)
* 父类 > 子类

结合下来的顺序:
【父类】静态代码块
【子类】静态代码块
父类构造代码块
父类构造方法
子类构造代码块
子类构造方法
"

25总结

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
final:关键字,最终的意思
final修饰的类:最终的类,不能被继承
final修饰的变量: 相当于是一个常量, 在编译生产.class文件后,该变量变为常量值
final修饰的方法: 最终的方法,子类不能重写,可以继承过来使用

————————————————————————————————————————————————————————————————————————————————————————

static : 关键字, 静态的意思
可以用来修饰类中的成员(成员变量,成员方法)
注意: 也可以用来修饰成员内部类
特点:
被静态所修饰的成员,会被所有的对象所共享
被静态所修饰的成员,可以通过类名直接调用,方便
Person.country = "中国";
Person.method();
注意事项:
静态的成员,随着类的加载而加载,优先于对象存在
在静态方法中,没有this关键字
静态方法中,只能调用静态的成员(静态成员变量,静态成员方法

————————————————————————————————————————————————————————————————————————————————————————

匿名对象:一个没有名字的对象
特点:
创建匿名对象直接使用,没有变量名
匿名对象在没有指定其引用变量时,只能使用一次
匿名对象可以作为方法接收的参数、方法返回值使用

————————————————————————————————————————————————————————————————————————————————————————

内部类:在一个类中,定义了一个新类,这个新的类就是内部类
class A {//外部类
class B{// 内部类
}
}
特点:
内部类可以直接访问外部类的成员,包含私有的成员

————————————————————————————————————————————————————————————————————————————————————————

包的声明与访问
类中包的声明格式:
package 包名.包名.包名…;
带有包的类,创建对象格式:包名.类名 变量名 = new包名.类名();
cn.itcast.Demo d = new cn.itcast.Demo();
导包的格式:
import 包名.类名;

————————————————————————————————————————————————————————————————————————————————————————

权限修饰符
public : 公共的
protected: 受保护的
default: 默认的(可省略)
private : 私有的

public protected default private
————————————————————————————————————————————————————————————————————————————————————————
"同一【类】中" √ √ √ √
————————————————————————————————————————————————————————————————————————————————————————
"同一包中(子类与无关类)" √ √ √
————————————————————————————————————————————————————————————————————————————————————————
"不同包的子类" √ √
————————————————————————————————————————————————————————————————————————————————————————
"不同包中的无关类"
————————————————————————————————————————————————————————————————————————————————————————


代码块:
局部代码块:定义在方法中的,用来限制变量的作用范围
构造代码块:定义在类中方法外,用来给对象中的成员初始化赋值
静态代码块:定义在类中方法外,用来给类的静态成员初始化赋值
————————————————————————————————————————————————————————————————————————————————————————

以下代码的输出结果是?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class B
{
public static B t1 = new B();
public static B t2 = new B();
{
System.out.println("构造块");
}
static
{
System.out.println("静态块");
}
public static void main(String[] args)
{
B t = new B();
}
}

答案: 构造块 构造块 静态块 构造块

开始时JVM加载B.class,对所有的静态成员进行声明,t1 t2被初始化为默认值,为null,又因为t1 t2需要被显式初始化,所以对t1进行显式初始化,初始化代码块→构造函数(没有就是调用默认的构造函数),咦!静态代码块咋不初始化?因为在开始时已经对static部分进行了初始化,虽然只对static变量进行了初始化,但在初始化t1时也不会再执行static块了,因为JVM认为这是第二次加载类B了,所以static会在t1初始化时被忽略掉,所以直接初始化非static部分,也就是构造块部分(输出’’构造块’’)接着构造函数(无输出)。接着对t2进行初始化过程同t1相同(输出’构造块’),此时就对所有的static变量都完成了初始化,接着就执行static块部分(输出’静态块’),接着执行,main方法,同样也,new了对象,调用构造函数输出(’构造块’)

并不是静态块最先初始化,而是静态域.
而静态域中包含静态变量、静态块和静态方法,其中需要初始化的是静态变量和静态块.而他们两个的初始化顺序是靠他们俩的位置决定的!
So!
初始化顺序是 t1 t2 静态块

-------------本文结束感谢您的阅读-------------
感谢您的支持,我会继续努力的!
0%