1.代码块的基本介绍
- 代码块又称初始化块,属于类中的成员(即是类的一部分)类似于方法,将逻辑语句封装在方法体中,通过{ }包围起来。
- 但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用
2.代码块的基本语法
[修饰符]{
代码
};
注意:
- 修饰符可选,要写的话,也只能写static。
- 代码块分为两类,使用static修 饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块。
- 逻辑语句可以为任何逻辑语句(输入,输出,方法调用,循环,判断)。
- 分号可以写,也可以省略。
3.代码块的好处:
1.相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化操作。
2.场景:如果多个构造器中有重复的语句,可以抽取到初始化带块中,提高代码的重复率。
4.实例(普通代码块):
三个构造器都有重复的语句,看起来特别的多余.
public class codeblock01 {
public static void main(String[] args) {
book book = new book("数据结构与算法");
System.out.println("========================");
book book1 = new book("kali从入门到入狱", 100, "呀吖呀");
}
}
class book{
private String name;
private double price;
private String author;
//3个构造器,构成了重载
public book(String name) {
System.out.println("书被打开了");
System.out.println("书被合上了");
System.out.println("构造器public book(String name)被调用");
this.name = name;
}
public book(String name, double price) {
System.out.println("书被打开了");
System.out.println("书被合上了");
this.name = name;
this.price = price;
}
public book(String name, double price, String author) {
System.out.println("书被打开了");
System.out.println("书被合上了");
System.out.println("构造器public book(String name, double price, String author)被调用");
this.name = name;
this.price = price;
this.author = author;
}
}
可以把一样的语句放到一个代码块中即可当我们不管调用哪个构造器,创建对象,都会调用代码块中的代码
public class codeblock01 {
public static void main(String[] args) {
book book = new book("数据结构与算法");
System.out.println("========================");
book book1 = new book("kali从入门到入狱", 100, "呀吖呀");
}
}
class book{
private String name;
private double price;
private String author;
//3个构造器,构成了重载
//三个构造器都有重复的语句,看起来特别的多余
//可以把一样的语句放到一个代码块中即可
{
System.out.println("书被打开了");
System.out.println("书被合上了");
}
public book(String name) {
//System.out.println("书被打开了");
//System.out.println("书被合上了");
System.out.println("构造器public book(String name)被调用");
this.name = name;
}
public book(String name, double price) {
//System.out.println("书被打开了");
//ystem.out.println("书被合上了");
this.name = name;
this.price = price;
}
public book(String name, double price, String author) {
//System.out.println("书被打开了");
//System.out.println("书被合上了");
System.out.println("构造器public book(String name, double price, String author)被调用");
this.name = name;
this.price = price;
this.author = author;
}
}
上面两个例子的运行结果都是:
书被打开了
书被合上了
构造器public book(String name)被调用
========================
书被打开了
书被合上了
构造器public book(String name, double price, String author)被调用
说明:代码块的调用是优先于构造器的!
5.静态代码块
static代码块叫静态代码块,作用是对类进行初始化它随着类的加载进行初始化,而且随着类的加载而被执行并且只会执行一次,如果是普通代码块,每次创建一个对象就执行一次。
实例①:
public class Test001 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
//静态代码块
static {
System.out.println("A的静态代码块正在被执行");
}
}
运行结果:
A的静态代码块正在被执行
得到结论
创建对象实例的时候也就是new的时候。
实例②:
public class Test002 {
public static void main(String[] args) {
A a = new A();
}
}
class A extends B{
//静态代码块
static {
System.out.println("A的静态代码块正在被执行");
}
}
class B {
static {
System.out.println("B的静态代码块正在被执行");
}
}
运行结果:
B的静态代码块正在被执行
A的静态代码块正在被执行
得到结论
创建子类对象实例,父类也会被加载,父类先被加载,子类后被加载。
实例③:
public class Test003 {
public static void main(String[] args) {
System.out.println(C.n1);
}
}
class C{
public static int n1 = 10000;
static {
System.out.println("C的静态代码块正在被执行");
}
}
运行结果:
C的静态代码块正在被执行
1000
得到结论
使用类的静态成员时,例如:静态成员,静态方法。静态代码块也要进行加载。
实例④:
public class Test004 {
public static void main(String[] args) {
D d = new D();
D d1 = new D();
}
}
class D{
static {
System.out.println("D的静态代码块被调用");
}
{
System.out.println("D的普通代码块被调用");
}
}
运行结果:
D的静态代码块被调用
D的普通代码块被调用
D的普通代码块被调用
说明:
静态代码块作用是对类进行初始化它随着类的加载进行初始化,而且随着累的加载而被执行并且只会执行一次,
如果是普通代码块,每次创建一个对象就执行一次。
实例⑤:
public class Test005 {
public static void main(String[] args) {
System.out.println(D.n1);
}
}
class D{
public static int n1 = 10000;
static {
System.out.println("D的静态代码块被调用");
}
{
System.out.println("D的普通代码块被调用");
}
}
运行结果:
D的静态代码块被调用
10000
说明
普通代码块需要在new对象的时候才会被调用,而且是每次创建新对象就会被调用。
而静态代码块,只要类加载了就会被调用。
6.类什么时候被加载?
- 创建对象实例的时候也就是new的时候。
- 创建子类对象实例,父类也会被加载,父类先被加载,子类后被加载。
- 使用类的静态成员时,例如:静态成员,静态方法。
7.创建一个对象时,在一个类中,调用顺序是怎么样的
- 先调用静态代码块和静态属性初始化。静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码和多个静态变量初始化,就按照定义的顺序执行。
- 调用普通代码块和普通属性的初始化。普通代码块和普通属性的优先级一样,这个和上面的一样。
3)最后在调用构造方法。
实例⑥:
public class codeblock03 {
public static void main(String[] args) {
AS as = new AS();
}
}
class AS{
static {
System.out.println("AS的静态代码块被调用");
}
private static int n1 = getN1();
public static int getN1(){
System.out.println("getN1方法被调用");
return 10000;
}
private int n2 = getN2();
public int getN2(){
System.out.println("getN2方法被调用");
return 90000;
}
{
System.out.println("AS的普通代码块被调用");
}
public AS(){
System.out.println("无参构造器被调用");
}
}
运行结果:
AS的静态代码块被调用
getN1方法被调用
getN2方法被调用
AS的普通代码块被调用
无参构造器被调用
8.存在继承关系时候调用的顺序
- 父类的静态代码块和静态属性(优先级一样)。
- 子类的静态代码块和静态属性(优先级一样)。
- 父类的普通代码块和普通属性初始化。
- 父类的构造方法。
- 子类的普通代码块和子类的普通属性初始化。
- 子类的构造方法。
注意: 静态代码块只能直接调用静态成员,普通代码块可以调用任意成员
实例⑦:
public class codeblock04 {
public static void main(String[] args) {
ZL zl = new ZL();
}
}
class ZL extends FL{
private static int A = getA();
private int A1 = getA1();
public static int getA(){
System.out.println("子类的静态方法被调用");
return 111;
}
public int getA1(){
System.out.println("子类的普通方法被调用");
return 222;
}
static {
System.out.println("子类的静态代码块被调用");
}
{
System.out.println("子类的普通代码块被调用");
}
public ZL(){
System.out.println("子类的构造器被调用");
}
}
class FL{
private static int B = getB();
private int B1 = getB1();
public static int getB(){
System.out.println("FL父类的静态方法被调用");
return 888;
}
public int getB1(){
System.out.println("FL父类的普通方法被调用");
return 999;
}
static {
System.out.println("FL父类的静态代码块被调用");
}
{
System.out.println("FL父类的普通代码块被调用");
}
public FL() {
System.out.println("FL父类的构造器被调用");
}
}
运行结果:
FL父类的静态方法被调用
FL父类的静态代码块被调用
子类的静态方法被调用
子类的静态代码块被调用
FL父类的普通方法被调用
FL父类的普通代码块被调用
FL父类的构造器被调用
子类的普通方法被调用
子类的普通代码块被调用
子类的构造器被调用