一、普通代码块
普通代码块就是直接在方法或语句中定义的代码块,具体示例如下:
1、创建一个测试类Test,里面有main()方法
package com.feisi.test;
public class Test {
public static void main(String[] args) {
{
int age=18;
System.out.println("我年龄是:"+age+"岁"); //局部代码块
}
int age=20;
System.out.println("他年龄是:"+age+"岁");
}
}
2、代码测试结果为:
3、分析:
(1)其实在上述代码中,每一对"{}"括起来的代码都称为一个代码块,Test类是一个大的代码块,接着是main方法代码块,在之中又定义了一个局部代码块。局部代码块在main方法之中进行了一个"分隔"作用,起到了限定作用域的作用。也就是为啥存在两个age变量,因为作用域不同,则无任何影响。
二、构造代码块
构造代码块是直接在类中定义的代码块,具体实例如下:
1、先新建一个父类叫做Person,并重写它的无参构造方法,Person的构造被调用的时候就是Person对象被创建了。里面还定义一个eat()方法,再在该类中写一个代码块(一对括号"{ }")。
package com.feisi.demo;
public class Person {
//代码块
{
//代码内容
System.out.println("Person代码块执行了.....");
}
public Person(){
System.out.println("Person对象被创建.....");
}
public void eat(){
System.out.println("吃饭中....."); //此方法要执行就是创建它的对象去调用
} //也就是这段代码的执行,取决于我什么时候调用
}
2、然后去定义一个子类Student,让子类去继承Person,再重写一下Student的无参构造,Student的构造被调用的时候就是Student对象被创建了,再在该类中写一个代码块(一对括号"{ }")。
package com.feisi.demo;
public class Student extends Person{
{
System.out.println("Student代码块被执行了.....");
}
public Student(){
System.out.println("Student对象被创建.....");
}
}
3、再定义一个测试类Test01,在里面创建子类Student对象。
package com.feisi.test;
import com.feisi.demo.Person;
import com.feisi.demo.Student;
//一个类的运行过程
public class Test01 {
public static void main(String[] args) {
Student student =new Student();
student.eat();
}
}
这里讲到一个类的运行问题:
(1)首先它肯定有相关的其他类,所以我们要导包。(若类都在同一包就不需要导包)
(2)然后因为main()方法在这个包中,也就是会加载相应的.class文件到方法区(内存区)。
(3)main()方法执行,压入栈区(那么首先执行里面的第一句话:Student student =new Student())
(4)那么接着就是要创建Student对象,其次我们讲过要先创建子类对象,就会先创建父类Person对象。那整个过程:在堆中创建Object对象,再在堆中创建Person对象[在Person对象中有一个引用super指向Object对象],若没有引用指向的Object对象,它将来会被回收,那么就将来找不到它,被垃圾回收器回收。
(5)接着在堆中创建Student对象[Student对象中也有一个引用super指向Person对象]。
(6)再者栈中的Student引用指向堆中的Student对象。
(7)main()方法执行完毕,main()方法出栈。
4、代码输出结果:
此时发现 :
(1)eat()代码在最后调用,最后执行没有问题。
(2) Student构造和Person构造方法被执行也能理解。
(3)写的两个代码块没有调用,但也被执行,我们发现它的执行时机是该类的构造方法之前。
5、如果再创建一个Student类的对象会变成咋样呢?
package com.feisi.test;
import com.feisi.demo.Person;
import com.feisi.demo.Student;
//一个类的运行过程
public class Test01 {
public static void main(String[] args) {
Student student1 =new Student();
student1.eat();
System.out.println("--------------------------------");
Student student2 = new Student();
student2.eat();
}
}
结果为:
此时又发现两个类的代码块又执行了一次,其执行时机也是分别在构造方法执行之前。
6、总结:
(1) 执行时机:对象被创建之前执行。也就是说构造代码块先于构造方法执行(这里和构造代码块写在前面还是后面没有关系)。
(2)每当实例化某个类的对象时,它会在执行构造方法之前执行构造代码块。
(3)作用:完成一些对象初始化工作。(也就是在每个对象创建之前都会调用它一次,那可以拿来完成一些对象初始化工作),如下:
package com.feisi.demo;
public class Student extends Person{
private char sex;
{
//也就是在每个对象创建之前,默认这个学生的性别是男生。
this.sex='男';
System.out.println("Student代码块被执行了.....");
}
public Student(){
System.out.println("Student对象被创建.....");
}
}
三、静态代码块 (static修饰)
在Java类中,用static关键字修饰的代码块称为静态代码块。在类被加载时,静态代码块就会执行。由于类只加载一次,所以静态代码块只执行一次。在程序中通常使用静态代码块对类的成员变量进行初始化。下面通过案例为大家讲解:
1、还是用上面的例子:(Student类和Person类),在各自类里面分别加上“static{ }”静态代码块
(1)Person类中加入这个代码块
static {
System.out.println("Person - static 代码块执行了.....");
}
(2) Student类中加入这个代码块
static {
System.out.println("Student - static 代码块执行了.....");
}
(3)最后输出结果:
我们发现:
静态代码块它们分别只执行一次,而且还是最最开始执行了一次。后面我去创建第二个对象它并没有去执行,也就是只在程序最开始执行一次,也就是在相应的.class文件加载到方法区时(也就是类加载时)。而且在前面导包的时候也声明了要用到哪个包里的那些类,也就是告诉程序要加载那些相应的.class文件到内存里。
2、总结:
(1)执行时机:在类加载时候,而且只执行一次。
(2)作用:在该类程序执行之前的初始化工作。(可以用静态代码块给静态成员变量赋初始值,也可以用静态方法给静态成员变量赋初始值,也可以直接给静态成员变量赋初始值)
package com.feisi.demo;
public class Student extends Person{
private char sex;
private static String sid; //学生学号
{
//也就是在每个对象创建之前,默认这个学生的性别是男生。
this.sex='男';
System.out.println("Student代码块被执行了.....");
}
static {
System.out.println("Student - static 代码块执行了.....");
sid="000000"; //在静态代码块中给静态成员变量赋值初始化
}
public Student(){
System.out.println("Student对象被创建.....");
}
}
四、所有总结
1、代码块的执行顺序:静态代码块——构造代码块———构造方法(由先到后)。
2、静态方法只能访问静态成员。