Java 代码块详解
Java 代码块详解
基本介绍
代码块
又称 初始化块, 是类的一部分,属于类中的成员,类似于方法,将逻辑语句封装在方法体中,通过 {} 封装起来。
但是代码块
没有方法名,没有返回,没有参数, 只有方法体,而且不用通过对象或类显示调用,而是加载类的时候,或创建对象的时候隐式调用。
基本语法
- 修饰符可选,并且修饰符只能为 static 。
- 代码块分为两类,用 static 修饰的为静态代码块,没有 static 修饰的为普通代码块。
- 代码块中可以写任何语句(输入,输出,方法调用,循环,判断等等)。
- ; 可以省略。
代码块示例
student类
public class Student {
private int id;
private String name;
private int age;
{
System.out.println("代码块被执行~~");
}
public Student(int id, String name, int age) {
System.out.println("构造器被调用~~~");
this.id = id;
this.name = name;
this.age = age;
}
}
BlockCodeTest类
public class BlockCodeTest {
// 代码块调用的顺序优先于构造器
public static void main(String[] args) {
Student s = new Student(1, "王昭君", 18);
}
}
运行结果:
通过运行结果我们发现,代码块调用的顺序优先于构造器的,所以,代码块
相当于另外一种形式的构造器,可以作为构造器的补充机制,做初始化的操作。
代码块使用细节
1. static代码块也叫静态代码块,作用就是对类进行初始化,它随类加载而执行,并且只会执行一次。如果是普通代码块(非静态代码块),每创建一个对象执行一次。
🚀类加载时机【 非常重要 】
1.创建实例对象时(new)
2.创建子类对象实例时,父类也会被加载
3.使用类的静态成员时(静态属性、静态方法)
代码示例1 【创建实例对象时(new)】
public class BlockCodeTest {
public static void main(String[] args) {
A a = new A();
}
}
class A {
static {
System.out.println("静态代码块被执行~~~");
}
}
运行结果
代码示例2 【创建子类对象实例时,父类也会被加载】
public class BlockCodeTest {
public static void main(String[] args) {
B b = new B();
}
}
class A {
static {
System.out.println("A类静态代码块执行~~~");
}
}
class B extends A {
static {
System.out.println("B类静态代码块执行~~~");
}
}
运行结果:
在实例化B类的对象时,其父类A类也被加载,并且父类加载先于子类。
代码示例3 【使用类的静态成员时】
public class BlockCodeTest {
public static void main(String[] args) {
System.out.println(A.num);
}
}
class A {
public static int num = 1;
static {
System.out.println("A静态代码块执行~~~");
}
}
运行结果:
调用静态变量,触发类加载,调用了A类的静态代码块。
代码示例4 【静态代码块在类加载时执行,并且只会执行一次】
public class BlockCodeTest {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
}
}
class A {
public static int num = 1;
static {
System.out.println("A静态代码块执行~~~");
}
}
运行结果:
static代码块, 是在类加载时执行的, 而且只会执行一次。
2. 普通的代码块,在创建对象实例时,会被隐式调用,被创建一次,就会被调动一次。
可以理解为在用类的构造器实例化对象的时候,构造器中有自动调用普通代码块机制。如果只是使用类的静态成员时,普通代码块并不会执行。
代码示例1
public class BlockCodeTest {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
A a3 = new A();
}
}
class A {
{
System.out.println("A普通代码块执行~~~");
}
}
运行结果:
实例化了3个对象,普通代码块执行了3次。
代码示例2
public class BlockCodeTest {
public static void main(String[] args) {
System.out.println(A.num);
}
}
class A {
public static int num = 1;
{
System.out.println("A普通代码块执行~~~");
}
static {
System.out.println("A静态代码块执行~~~");
}
}
运行结果:
使用类的静态成员,普通代码块并不会执行。
🚀小结:
1.static代码块是在类加载时执行的,并且只会执行一次。
2.普通代码块是在创建对象的时候调用的,与类加载无关,创建一次对象,调用一次。
3. 创建一个对象时,在一个类中的调用顺序:
1) 调用静态代码块和静态属性的初始化(静态代码块和静态属性的初始化调用的优先级一样,如果有多个静态代码块和多个静态属性初始化,则按照他们的定义顺序调用)
2) 调用普通代码块和普通属性的初始化(普通代码块和普通属性的初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按照他们定义的顺序调用)
3)最后调用构造方法
代码示例
public class BlockCodeTest {
public static void main(String[] args) {
A a = new A();
}
}
class A {
//静态属性
private static int num1 = getVal1();
//普通属性
private int num2 = getVal2();
public A() {
System.out.println("构造器被执行...");
}
//静态代码块
static {
System.out.println("A静态代码块儿执行~~");
}
//普通代码块
{
System.out.println("A普通代码块儿执行");
}
public static int getVal1() {
System.out.println("getVal1执行...");
return 1;
}
public int getVal2() {
System.out.println("getVal2执行...");
return 2;
}
}
运行结果:
实例化一个A对象,首先产生类加载,完成静态属性的初始化和执行静态代码块(静态代码块和静态属性的初始化调用的优先级一样,因为A类中静态属性的初始化在静态代码块的前面,所以先完成静态属性的初始化),之后执行构造器,因为构造器中有自动调用普通代码块机制和初始化普通属性的机制,所以先完成普通属性的初始化和执行普通代码块(当然这里也没有优先级),最后执行构造器中的代码。
4. 构造器的前面其实隐藏了super() 和 调用普通代码块
代码示例
public class BlockCodeTest {
public static void main(String[] args) {
B b = new B();
}
}
class A {
{
System.out.println("A类的普通代码块被执行...");
}
public A() {
//super()
//调用普通代码块
System.out.println("A类的构造器被调用...");
}
}
class B extends A {
{
System.out.println("B类的普通代码块被执行...");
}
public B() {
//super()
//调用本类的代码块
System.out.println("B类的构造器被调用...");
}
}
运行结果:
调用B类构造器的时候,因为构造器中有隐含的super()和调用本类的普通代码块,所以,先执行其父类A类的构造器,其A类同时也有隐含的super()和调用本类的普通代码块,其父类为object,没有相关操作,最后执行结果如上。
5. 有继承关系时,他们的 静态代码块,静态属性的初始化 ,普通属性的初始化 , 普通代码块, 构造方法的调用顺序如下:
① 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
② 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
③ 父类的普通代码块和普通属性 (优先级一样,按定义顺序执行)
④ 父类的构造方法
⑤ 子类的普通代码块和普通属性 (优先级一样,按定义顺序执行)
⑥ 子类的构造方法
代码示例
public class BlockCodeTest {
public static void main(String[] args) {
B b = new B();
}
}
class A {
private static int num1 = getVal1();
private int num2 = getVal2();
{
System.out.println("A类的普通代码块被执行...");
}
static {
System.out.println("A类的静态代码块被执行...");
}
public A() {
System.out.println("A类构造器被执行");
}
public static int getVal1() {
System.out.println("A类静态属性初始化...");
return 1;
}
public int getVal2() {
System.out.println("A类普通属性初始化...");
return 2;
}
}
class B extends A {
private static int num1 = getVal11();
private int num2 = getVal22();
{
System.out.println("B类的普通代码块被执行...");
}
static {
System.out.println("B类的静态代码块被执行...");
}
public B() {
System.out.println("B类构造器被执行");
}
public static int getVal11() {
System.out.println("B类静态属性初始化...");
return 1;
}
public int getVal22() {
System.out.println("B类普通属性初始化...");
return 2;
}
}
运行结果:
6. 静态代码块只能调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
相关文章
- 跟阿根一起学Java Web开发一:开发环境搭建及JSPGen基础配置
- 大杂烩 -- Java内存布局【图】以及java各种存储区【详解】
- 自学5个月Java找到了9K的工作,我的方式值得大家借鉴
- Java开发环境的搭建以及使用eclipse从头一步步创建java项目
- 基于 Java+MySQL 的桌面 GUI 图书管理系统【100010417】
- java提取字符串数字,Java获取字符串中的数字
- Java线程锁,synchronized、wait、notify详解--java 管程
- java如何设置文件的权限
- java并发Exchanger的使用
- 生产者消费者问题理解与Java实现
- Java_类似java.lang.VerifyError: Expecting a stackmap frame at branch target 22 in method的解决方法
- 浅析Java对集合进行操作时报java.util.ConcurrentModificationException并发修改异常问题:产生原因、单线程/多线程环境解决、CopyOnWriteArrayList线程安全的ArrayList、fail-fast快速失败机制防止多线程修改集合造成并发问题
- Java基础篇:四种代码块详解
- 华为OD机试 - 分班(Java) | 机试题+算法思路+考点+代码解析 【2023】
- 【JAVA】浅谈java枚举类
- java.lang.NoSuchMethodError: net.sf.cglib.core.Signature
- Java POI组件——写Excel