前言:
相信很多小伙伴在学习java的时候,看不懂代码翻看别人的代码的时候看到一个用大括号括起来的一段代码,却不知道他是干什么的,怎么用的,更加看不懂了,今天我就带大家来了解一下这个神秘的代码块。
目录
一、代码块的基本概念
代码块又称为初始化块,属于类中的成员(即是类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。但是和方法不同的是,没有方法名,没有返回,没有参数,只有方法体,而且不通过对象或类显示调用,而是加载类时,或创建对象时隐式调用。
二、代码块的基本语法
[修饰符] {代码};
注意:
1.修饰符可选,要写也只能写static
2.代码块分为两类,使用static修饰的叫静态代码块,没有得叫普通代码块
3.逻辑语句可以为任何逻辑语句(输入,输出,方法调用,循环,判断等)
4.;号可以写上,也可以省略
三、代码块的好处
我们为什么要使用代码块呢?原因有二:
1.相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
2.如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性
接下来我们用代码来解释
package com.CodeBlock;
class Movie {
public static void main(String[] args) {
CodeBlock cb = new CodeBlock("功夫熊猫");
}
}
/*
1.下面的三个构造器都有相同的语句
2.这样的代码看齐来比较冗余
3.这时候我们就可以把相同的语句。放入到一个代码块中即可
4.这样当我们不管调用那个构造器,创建对象,都会优先调用代码块中的内容
5.代码块的调用优先于构造器
*/
public class CodeBlock {
private String name;
private double price;
private String director;
{
System.out.println("电影屏幕开启。。。。");
System.out.println("广告开启。。。。");
System.out.println("电影正式开始。。。。");
};
public CodeBlock(String name) {
System.out.println("(String name)被调用");
this.name = name;
}
public CodeBlock(String name, double price) {
// System.out.println("电影屏幕开启。。。。");
// System.out.println("广告开启。。。。");
// System.out.println("电影正式开始。。。。");
this.name = name;
this.price = price;
}
public CodeBlock(String name, double price, String director) {
// System.out.println("电影屏幕开启。。。。");
// System.out.println("广告开启。。。。");
// System.out.println("电影正式开始。。。。");
this.name = name;
this.price = price;
this.director = director;
}
}
输出语句
电影屏幕开启。。。。
广告开启。。。。
电影正式开始。。。。
(String name)被调用
可以看到我们放在代码块中的内容被是随着对象的创建而加载,解决了我们代码重复的问题。
因此代码块的内容是先于构造器的输出的,而且这么做的好处就是我们不论是调用哪一个构造器,我们的代码块的内容是始终可以首先加载的。这也符合我们本身的需求,避免了代码重复写在每一个构造器中。
四、代码块使用的注意事项
1.static代码块也叫静态代码块,作用就是对类进行初始化,,而且他随着类的加载而执行,并且只会执行一次;如果是普通代码块,每创建一个对象,就执行。
2.类什么时候被加载
(1).创建对象实例时(new)
示例代码
public class Demo1 {
public static void main(String[] args) {
//1.创建对象实例时(new)
AA a = new AA();
}
}
class AA {
//静态代码块
static {
System.out.println("AA 的静态代码块被调用");
};
}
输出:
AA 的静态代码块被调用
(2).创建子类对象实例,父类也会被加载
示例代码
public class Demo1 {
public static void main(String[] args) {
//1.创建对象实例时(new)
// AA a = new AA();
//2.创建子类对象实例,父类也会被加载
BB b = new AA();
}
}
class BB {
//静态代码块
static {
System.out.println("BB 的静态代码块被调用");
};
}
class AA extends BB{
//静态代码块
static {
System.out.println("AA 的静态代码块被调用");
};
}
输出:
BB 的静态代码块被调用
AA 的静态代码块被调用
(3).使用类的静态成员时(静态属性,静态方法)
示例代码
public class Demo1 {
public static void main(String[] args) {
// 3.使用类的静态成员时(静态属性,静态方法)
System.out.println(CC.a);
}
}
class CC {
//静态属性
public static int a = 1;
//静态代码块
static {
System.out.println("BB 的静态代码块被调用");
};
}
输出
BB 的静态代码块被调用
3.普通的代码块,在创建对象实例时,会被隐式调用,被创建一次,调用一次。如果只是使用类的静态成员时,普通代码块不会被执行
示例代码
public class Demo2 {
public static void main(String[] args) {
//1普通的代码块,在创建对象实例时,会被隐式调用,被创建一次,调用一次。
AB a1 = new AB();
AB a2 = new AB();
System.out.println("++++++++++");
//如果只是使用类的静态成员时,普通代码块不会被执行
System.out.println(AB.d);
}
}
class AB {
//静态属性
public static int d = 222;
//普通代码块
{
System.out.println("AB 普通代码块被调用");
}
}
输出结果
AB 普通代码块被调用
AB 普通代码块被调用
++++++++++
222
重点(敲黑板)
(1).static代码块是在类加载时,执行,只会执行一次
(2).普通代码块是在创建对象时调用的,创建一次,调用一次
4.创建一个对象时,在一个类调用顺序是
(1).调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个代码块和多个静态变量初始化,则按他们定义的顺序调用)
(2).调用普通代码块和普通属性初始化(注意:普通代码块和普通属性初始化的调用优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义的顺序调用)
(3).调用构造方法
示例代码
package com.CodeBlock;
/**
* 4.创建一个对象时,在一个类调用顺序是
* 1.调用静态代码块和静态属性初始化
* (注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个代码块和多个静态变量初始化,则按他们定义的顺序调用)
* 2.调用普通代码块和普通属性初始化
* (注意:普通代码块和普通属性初始化的调用优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义的顺序调用)
* 3.调用构造方法
*/
public class Demo3 {
public static void main(String[] args) {
VV a = new VV();
}
}
class VV {
//空参构造器
public VV() {
System.out.println("VV的构造方法被调用");
}
//普通代码块
{
System.out.println("VV的普通代码块02被调用");
};
//普通属性初始化
public int a = getA();
//静态代码块
static {
System.out.println("VV的静态代码块01被调用");
};
//静态属性初始化
public static int c = getC();
public static int getC() {
System.out.println("getC()的静态属性初始化被调用");
return 100;
}
public int getA() {
System.out.println("getA()的普通属性初始化被调用");
return 200;
}
}
输出结果
VV的静态代码块01被调用
getC()的静态属性初始化被调用
VV的普通代码块02被调用
getA()的普通属性初始化被调用
VV的构造方法被调用
5.构造器的最前面其实隐含了super() 和 调用普通代码块。静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块的执行。普通代码块的调用是优先于构造器的调用
示例代码
package com.Test01;
/**
* 5.构造器的最前面其实隐含了super() 和 调用普通代码块。
* 静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块的执行。
* 普通代码块的调用是优先于构造器的调用
* 示例代码
* 输出结果
*/
public class CodeBlock {
public static void main(String[] args) {
new BB();//1."类AA的代码块被调用"2.类BB的无参构造器被调用3.类BB的代码块被调用4.类BB的无参构造器被调用
}
}
class AA {
{
System.out.println("类AA的代码块被调用");
}
public AA (){
//super()
System.out.println("类BB的无参构造器被调用");
}
}
class BB extends AA {
{
System.out.println("类BB的代码块被调用");
}
public BB (){
//super()
System.out.println("类BB的无参构造器被调用");
}
}
输出结果
类AA的代码块被调用
类BB的无参构造器被调用
类BB的代码块被调用
类BB的无参构造器被调用
6.创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
(1)、父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
(2)、子类的静态代码块和静态属性(优先级一样,按定义顺序调用)
(3)、父类的普通代码块和普通属性初始化(优先级一样,按定义顺序调用)
(4)、父类的构造方法
注意,之所以这里先调用父类的普通代码块,是因为构造方法下隐藏了super()和普通代码块
(5)、子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
(6)、子类的构造方法
示例代码
package com.Test;
class Demo {
public static void main(String[] args) {
new BB();
}
}
public class AA {
static {
System.out.println("AA的静态代码块被调用");//1
};
public static int a = getA();
public static int getA() {
System.out.println("getA被调用");//2
return 10;
}
{
System.out.println("AA的普通代码块被调用");//5
};
public int c = getC();
public int getC() {
System.out.println("getC被调用");//6
return 30;
}
public AA (){
//super()
//普通代码块
System.out.println("AA的构造方法被调用");//7
}
}
class BB extends AA {
static {
System.out.println("BB的静态代码块被调用");//3
};
public static int a = getB();
public static int getB() {
System.out.println("getB被调用");//4
return 20;
}
{
System.out.println("BB的普通代码块被调用");//8
};
public int c = getD();
public int getD() {
System.out.println("getD被调用");//9
return 40;
}
public BB (){
//super()
//普通代码块
System.out.println("BB的构造方法被调用");//10
}
}
输出结果
AA的静态代码块被调用
getA被调用
BB的静态代码块被调用
getB被调用
AA的普通代码块被调用
getC被调用
AA的构造方法被调用
BB的普通代码块被调用
getD被调用
BB的构造方法被调用
7、静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员
示例代码
package com.Test;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public class TestDemo {
public static void main(String[] args) {
new Test();
}
}
class Test{
private static int a = 100;
private int b = 200;
private static void get() {
}
private void getD() {
}
//普通代码块可以调用任意成员
{
System.out.println(a);
System.out.println(b);
get();
getD();
}
//静态代码块只能调用静态成员
static{
System.out.println(a);
// System.out.println(b);报错
get();
// getD();报错
}
}
输出结果
那么输出结果大家可以在下方投票处选择,下期公布答案哦!不要忘了三连加关注啊亲