代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类)。
代码块按照有无static修饰,分为两种:静态代码块(有static修饰)、实例代码块(没有static修饰,也叫实例初始化块)。
静态代码块
为什么需要静态代码块
通常,我们会在声明时直接初始化静态变量。然而,如果静态变量在初始化时需要多条语句的逻辑,我们可以使用静态代码块来代替。
总的来说,使用静态代码块的主要原因有:
- 初始化静态变量时需要一些额外的逻辑,而不仅仅是赋值。
- 用自定义异常处理来初始化静态变量。
静态代码块的格式
static {代码}
静态代码块的特点
静态代码块在类加载时自动执行,且只会执行一次。
静态代码块的作用
完成类的初始化,例如,类变量的初始化。
示例
示例:声明一个静态代码块
定义一个Student类:
package com.team.block.e1;
public class Student {
static int number = 60;
// 静态代码块
static {
System.out.println("Student中的静态代码块被执行了");
}
}
定义测试类Test:
package com.team.block.e1;
public class Test {
public static void main(String[] args) {
System.out.println(Student.number);
}
}
运行结果:
示例:演示静态代码块只会被执行一次
定义一个Student类:
package com.team.block.e1;
public class Student {
static int number = 60;
// 静态代码块
static {
System.out.println("Student中的静态代码块被执行了");
}
}
定义测试类Test:
package com.team.block.e1;
public class Test {
public static void main(String[] args) {
System.out.println(Student.number);
System.out.println(Student.number);
System.out.println(Student.number);
}
}
运行结果:
示例:利用静态代码块对类变量初始化
定义Student类:
package com.team.block.e1;
import java.util.ArrayList;
public class Student {
static ArrayList<String> hobbies = new ArrayList<>();
// 静态代码块
static {
System.out.println("Student中的静态代码块被执行了");
hobbies.add("游泳");
hobbies.add("跑步");
hobbies.add("吃海鲜");
}
}
定义测试类Test:
package com.team.block.e1;
public class Test {
public static void main(String[] args) {
System.out.println(Student.hobbies);
}
}
运行结果:
示例:jdk中的java.net.Socket类利用静态代码块对类变量初始化
实例代码块(也叫实例初始化块)
实例代码块的格式
{代码}
实例代码块也称为实例初始化块,它是一段在类内部声明的代码,用于初始化实例数据成员。实例初始化块对每个对象只执行一次,可以用来为实例变量设置初始值。
实例初始化块与Java的构造器类似,但其执行和使用方式不同。
实例代码块的特点
- 实例初始化块在对象创建时被调用一次。
- 实例初始化块在任何对象的构造函数被调用之前执行。
- 在子类的情况下,实例初始化块将在超类构造函数调用之后被调用。
- 实例初始化块可用于执行多条语句。
- 实例初始化块通常用于实例化多个值字段,如数组。
实例代码块的用途
以下是Java中实例初始化块的用途:
- 用于初始化实例变量。
- 用于初始化代码中使用的资源。
- 用于执行实例变量的动态初始化。
- 用于为多个构造器使用共同的初始化逻辑,减少构造器中重复代码的编写。
示例
示例:声明一个实例初始化块
创建一个Foo类:
package com.team.block.e2;
public class Foo {
int a;
{
a = 10;
}
}
创建一个测试类Test:
package com.team.block.e2;
public class Test {
public static void main(String[] args) {
Foo foo1 = new Foo();
System.out.println(foo1.a);
}
}
运行结果:
示例:演示实例初始化块和构造器的调用顺序
定义Foo类:
package com.team.block.e2;
public class Foo {
{
System.out.println("Foo的实例初始化块被调用了");
}
public Foo() {
System.out.println("Foo的构造器被调用了");
}
}
定义测试类Test:
package com.team.block.e2;
public class Test {
public static void main(String[] args) {
Foo foo1 = new Foo();
}
}
运行结果:
示例:演示构造器是否覆盖实例初始化块
在这个例子中,我们展示了在实例初始化块中初始化的值被对象构造器覆盖了。当使用new操作符创建对象时,实例初始化块和构造函数都会被调用。
创建一个Foo类:
package com.team.block.e2;
public class Foo {
int a;
{
System.out.println("Foo的实例初始化块被调用了");
a = 10;
}
public Foo() {
System.out.println("Foo的构造器被调用了");
a = 20;
}
}
创建一个测试类Test:
package com.team.block.e2;
public class Test {
public static void main(String[] args) {
Foo foo = new Foo();
System.out.println(foo.a);
}
}
运行结果:
示例:演示实例初始化块在每次生成一个对象的时候都会被执行一次
Foo类:
package com.team.block.e2;
public class Foo {
int a;
{
System.out.println("Foo的实例初始化块被调用了");
}
public Foo() {
System.out.println("Foo的构造器被调用了");
}
}
测试类Test:
package com.team.block.e2;
public class Test {
public static void main(String[] args) {
Foo foo1 = new Foo();
System.out.println("---------------------");
Foo foo2 = new Foo();
}
}
运行结果:
示例:演示实例初始化块、无参构造器、有参构造器
类Foo:
package com.team.block.e2;
public class Foo {
private int a;
{
System.out.println("Foo的实例初始化块被调用了");
}
// 无参构造器
public Foo() {
System.out.println("Foo的无参构造器被调用了");
}
// 有参构造器
public Foo (int a) {
System.out.println("Foo的有参构造器被调用了");
}
}
测试类Test:
package com.team.block.e2;
public class Test {
public static void main(String[] args) {
Foo foo1 = new Foo();
System.out.println("---------------------");
Foo foo2 = new Foo(10);
}
}
运行结果:
示例:演示实例初始化块和父类构造器的执行顺序
在这个例子中,在输出中,可以验证被调用的代码块的顺序。首先调用父类的构造器,然后调用子类的实例初始化块,该块初始化一个实例变量,接着调用子类的构造器。
父类SuperFoo:
package com.team.block.e2;
public class SuperFoo {
public SuperFoo() {
System.out.println("SuperFoo的构造器被调用了");
}
}
子类Foo:
package com.team.block.e2;
public class Foo extends SuperFoo {
int a;
{
System.out.println("Foo的实例初始化块被调用了");
a = 10;
}
public Foo() {
System.out.println("Foo的构造器被调用了");
}
}
测试类Test:
package com.team.block.e2;
public class Test {
public static void main(String[] args) {
Foo foo = new Foo();
System.out.println("a的值是:" + foo.a);
}
}
运行输出: