目录
2.静态代码块(定义在方法体外、类里面且须用 static 修饰的代码块)
4.同步代码块( run 方法内使用 synchronize 修饰的代码块)
代码块(阉割的方法:只剩下方法体)
它也叫初始化块,方法具有专门的方法名还有返回值、参数、方法体。但代码块只有方法体,所以说它是“阉割的方法”。(方法体就是用{ }包围起来的东东)
根据代码块的相对位置和关键字的修饰可以细分成四种:
1.普通代码块(定义在方法体内且无修饰符的代码块)
public class Test {
public static void main(String[] args) {
{
int a = 10;
System.out.println("我是普通代码块");
}
// 可以看到以上这个普通代码块是定义在 main() 方法里面的
}
}
2.静态代码块(定义在方法体外、类里面且须用 static 修饰的代码块)
public class Test {
public static void main(String[] args) {
System.out.println("我这里是 main() 方法内哦!");
}
static {//使用了static 修饰了
String str = "我是静态代码块";
}
// 可以看到以上这个静态代码块位于 Test 类里面,而又在方法之外
}
3.构造代码块(定义在方法体外、类里面但不用修饰的代码块)
public class Test {
{
System.out.print("我是构造代码块");
}
// 显然可见,以上的构造代码块在 Test 类里面,但又不在方法里面
public static void main(String[] args) {
System.out.print("我是 main 方法!");
}
}
构造代码块也叫:非静态代码块或实例代码块。
4.同步代码块( run 方法内使用 synchronize 修饰的代码块)
public class Demo_Test implements Runnable {
@Override
public void run() {
synchronized (this) {
System.out.println("我是同步代码块");
}
}
}
必须用在线程情况下,所以我又叫它线程代码块/锁代码块,它是所有代码块中破例拥有传递参数的代码块,而它的传递参数就是“锁”对象。
普通代码块 | 构造代码块 | 静态代码块 | |
---|---|---|---|
初始化时机(执行时机) | new对象时 | new对象时 | 加载类时 |
其访问范围(不论封装的限制) | 任何资源(包括静态资源) | 仅限于静态资源 | |
定义位置 | 方法体内 | 类里面、方法体外 |
扩展1:普通代码块和构造代码块的区别是:
普通代码块 | 构造代码块 | |
---|---|---|
定义位置 | 方法体里 | 类里面、方法体外 |
执行顺序比较 | 普通代码块 < 构造代码块 | |
调用时机 | 调用其方法时 | 构造其类的对象时 |
扩展2:构造代码块和构造函数(构造方法)的区别:
构造代码块 | 构造函数(构造方法) | |
---|---|---|
不同点 | 没有方法名 | 具有和类名一致的方法名 |
相同点 | 都没有返回值 | |
是否有参数 | 没有参数列表 | 有参数列表 |
首先讲执行顺序前:一般默认执行顺序就是从上至下。
执行顺序:静态代码块 => 构造代码块 => 普通代码块
如果构造函数和构造代码块要比较执行顺序的话:那么还是构造代码块更优先,但次于静态代码块。
静态代码块/构造代码块 | 构造函数 | |
---|---|---|
调用权限 | 公有的 | 私有的 |
执行次数 | 执行一次全类通用 | 每new对象要执行一次 |
构造代码块和静态代码块就像户口本,造出一本全家通用,即家里面只要第一人有了户口本了他的家人就不必再造新户口本了(跟着用就行)。
而构造函数就像身份证,每个人一出生就必须专门拥有一个身份证,属于私有物品。
(关于同步代码块的执行顺序这里暂不讨论,而普通代码块是随其从属的方法的执行而执行的)
继承和代码块的碰撞!
这里主要查看new对象初始化的顺序,直接上代码!
public class Sequence {
public static void main(String[] args) {
A a = new A();
B b = new B();
// 分别初始化了 a 和 b 对象,看看打印结果吧!
}
}
class A {
static {
System.out.println("我是A的静态代码块");
}
{
System.out.println("我是A的构造代码块");
}
public A() {
System.out.println("我是A的构造函数(构造方法)");
{
System.out.println("我是位于A的构造方法里的普通代码块");
}
}
}
class B extends A {
static {
System.out.println("我是B的静态代码块");
}
{
System.out.println("我是B的构造代码块");
}
public B() {
super();
System.out.println("我是B的构造函数(构造方法)");
{
System.out.println("我是位于B的构造方法里的普通代码块");
}
}
}
打印结果附上:
解析:
可以从头看到A类的静态代码块、构造代码块、构造函数以及其普通代码块的执行顺序是符合我前面写的逻辑。(已知普通代码块是随方法的执行而执行的。所以构造函数执行时,普通代码块就紧跟在它的屁股后面)
而为什么A这个父类的构造对象的代码部分(构造代码块、构造方法)会执行了两遍呢?这个疑惑你早已经在我这篇文章的关于继承的部分中得知了吧!