• 理解

初始化块又称为代码块。属于类中的第四大成员。本质上是一个方法,它也有方法体,但没有方法名,没有参数,没有返回,而且也不是通过对象或类名显式调用,而是通过隐式调用

是构造器的补充

语法

[修饰符]{
方法体
}

注意:

①修饰符只能是static,使用static修饰的初始化块称为静态初始化块

没有使用static修饰的初始化块称为普通初始化块

//静态初始化块
static{ }
//普通初始化块
{ }

②方法体中可以为任意逻辑语句,包含输入、输出、变量、运算等

  • 好处

1、和构造器很像,都是用于初始化信息

2、当多个构造器中有重复的语句,可以将这些重复的语句往上提取到初始化块中,提高代码的重用性

  • 特点

1、静态初始化块的调用时机:加载类
普通初始化块的调用时机:创建对象

初始化块示例:

class InitDemo{

    String name;
int age;
double height; {
System.out.println("初始化语句");
} public InitDemo(){ } public InitDemo(String name) {
super();
this.name = name;
} public InitDemo(String name, int age) {
super();
this.name = name;
this.age = age;
} public InitDemo(String name, int age, double height) {
super();
this.name = name;
this.age = age;
this.height = height;
}
}

2、静态初始化块只会调用一次,随着类的加载而加载,(类只加载一次)

普通初始化块可以调用多次,随着对象的创建而加载

/*
*此类用于演示初始化块的特点2:
*静态初始化块只能被调用一次,因为类只能加载一次。
*普通初始化块可以被调用多次,因为可以创建多个对象
*/
public class TestInit2 { public static void main(String[] args) {
// System.out.println(InitDemo2.a);//加载类
new InitDemo2();
new InitDemo2();
new InitDemo2();
new InitDemo2();
new InitDemo2();
}
}
class InitDemo2{
static int a =100; { System.out.println("我是普通初始化块");
}
static{
System.out.println("我是静态初始化块");
}
}

3、一个类中可以有多个静态初始化块和多个普通初始化块

静态初始化块的执行要早于普通初始化块
同一个类型的初始化块的执行顺序取决于定义的先后顺序!

/*
* 此类用于演示初始化块的特点3:
* 一个类中允许有多个普通初始化块和静态初始化块,则执行顺序:
* 静态初始化块————普通初始化块
* 同一个类别的初始化块,执行顺序取决于定义的先后顺序
*/
public class TestInit3 { public static void main(String[] args) {
// System.out.println(InitDemo2.a);//加载类
new InitDemo3();//加载+创建对象 } }
class InitDemo3{
{
System.out.println("我是普通初始化块1");
}
static{
System.out.println("我是静态初始化块1");
} {
System.out.println("我是普通初始化块2");
}
{
System.out.println("我是普通初始化块3");
}
static{
System.out.println("我是静态初始化块2");
}
static{
System.out.println("我是静态初始化块3");
} }

输出:

我是静态初始化块1
我是静态初始化块2
我是静态初始化块3
我是普通初始化块1
我是普通初始化块2
我是普通初始化块3

4、一个类中如果有:静态初始化块、普通初始化块、普通属性初始化、静态属性初始化、构造器

执行顺序:
静态初始化块 | 静态属性初始化 > 普通初始化块 | 普通属性初始化 > 构造器

/*
* 此类用于演示初始化块的特点4:
* 如果一个类中有普通属性初始化、静态属性初始化、普通初始化块、静态初始化块、构造器,则执行顺序:
* 静态属性初始化|静态代码块——>普通属性初始化|普通代码块——>构造器
* 同一个类别的属性初始化和代码块的执行顺序取决于定义的先后顺序
*
*/
public class TestInit4 { public static void main(String[] args) {
InitDemo4 id = new InitDemo4();
} }
class InitDemo4{ public InitDemo4(){
System.out.println("我是构造器");
}
String a=msg("普通属性初始化1"); public static String msg(String info){
System.out.println(info);
return info;
}
static{
System.out.println("静态初始化块2");
}
static String b=msg("静态属性初始化1"); {
System.out.println("我是普通初始化块1");
} String c=msg("普通属性初始化2"); {
System.out.println("我是普通初始化块2");
}
static String d=msg("静态属性初始化2"); static{
System.out.println("静态初始化块1");
}
}

输出:

静态初始化块2
静态属性初始化1
静态属性初始化2
静态初始化块1
普通属性初始化1
我是普通初始化块1
普通属性初始化2
我是普通初始化块2
我是构造器

5、有父子类

执行顺序:

爷爷类的静态初始化块 | 静态属性初始化 >

父类静态初始化块 | 静态属性初始化 >

子类静态初始化块 | 静态属性初始化 >

爷爷类普通初始化块 | 普通属性初始化 > 构造器 >

父类普通初始化块 | 普通属性初始化 > 构造器 >

子类普通初始化块 | 普通属性初始化 > 构造器

/*
* 此类用于演示初始化块的特点5:
* 如果父子类中都有普通属性初始化、静态属性初始化、普通初始化块、静态初始化块、构造器,
* 则执行顺序:
* 爷爷类的静态属性初始化|静态代码块——>父类的静态属性初始化|静态代码块——>子类的静态属性初始化|静态代码块——>
* 爷爷类的普通属性初始化|普通代码块——>爷爷类的构造器——>父类的普通属性初始化|普通代码块——>父类的构造器——>子类的普通属性初始化|普通代码块——>子类的构造器
* 同一个类别的属性初始化和代码块的执行顺序取决于定义的先后顺序
*
*/
public class TestInit5 { public static void main(String[] args) {
InitDemo5 id = new InitDemo5();
} }
class Grand{
public Grand(){ // System.out.println("爷爷类的普通代码块");
System.out.println("我是爷爷类的构造器");
}
String a=fun("爷爷类的普通属性初始化"); public static String fun(String info){
System.out.println(info);
return info;
}
static{
System.out.println("爷爷类的静态代码块");
} {
System.out.println("爷爷类的普通代码块");
} static String d=fun("爷爷类的静态属性初始化");
}
class Father extends Grand{
public Father(){
// System.out.println("爷爷类的普通代码块");
System.out.println("我是爷爷类的构造器");
// System.out.println("父类的普通代码块");
System.out.println("我是父类的构造器");
}
String a=method("父类的普通属性初始化"); public static String method(String info){
System.out.println(info);
return info;
}
static{
System.out.println("父类的静态代码块");
} {
System.out.println("父类的普通代码块");
} static String d=method("父类的静态属性初始化"); }
class InitDemo5 extends Father{ public InitDemo5(){
System.out.println("我是子类的构造器");
}
String a=msg("子类的普通属性初始化"); public static String msg(String info){
System.out.println(info);
return info;
}
static{
System.out.println("子类的静态代码块");
} {
System.out.println("子类的普通代码块");
} static String d=msg("子类的静态属性初始化");
}

6、静态初始化块中遵循静态成员的特点,只能直接访问静态成员!

7、初始化位置

普通的常量属性,初始化必须在声明时或构造器或普通代码块中

静态的常量属性,初始化必须在声明时或静态代码块中

示例:

class A{
final int x;
final static int y;
public A(){
y=10;
x=100; // × final变量初始化后不可重新赋值
}
{
x=100;
y=10; // × final static修饰的静态常量只能在static静态初始化块中初始化
}
}

第二种:

class A{
final int x;
final static int y;
public A(){
y=10; // × final变量初始化后不可重新赋值
x=100;
}
static{
x=100; // × static静态初始化块不可调用普通变量
y=10;
}
}

【总结】

类的对象创建包括:加载和创建两部分。

加载中将所有静态的属性、静态初始化块执行

创建对象中将所有普通属性、普通初始化块执行,再执行构造方法

【面试题一】

public class Teacher {

    public static void main(String[] args) {
new Teacher("john");  // ⑥
}
String name ;
public Teacher(String string) {
this.name=string;
System.out.println("构造器:"+name);  // ④ 构造器执行 // ⑧ 构造器执行
}
static {
System.out.println("嘿嘿");  // ①
}
static Teacher t = new Teacher("鸠摩智");  // ② 加载时发现还需要加载不会再加载
{
System.out.println("哈哈哈:"+name);  // ③ 此时name(鸠摩智)还没赋值,为null // ⑦ 加载结束,但name(john)没被赋值,为null
}
static{
System.out.println("呵呵");  // ⑤ 继续加载类,加载结束
}
}

输出:

嘿嘿
哈哈哈:null
构造器:鸠摩智
呵呵
哈哈哈:null
构造器:john

【面试题二】

public class MyClass {
static int x,y;  // ① x=0, y=0
static{
int x=5;    // ② x = 5(局部变量,与static无关)
x--;      // ③ x = 4(局部变量,与static无关)
}
static{
x--;      // ④ x = -1
} public static void main(String[] args) {
x--;      // ⑤ x = -2
myMethod() ;  // ⑥
System.out.println(x+y + ++x);  // ⑧ 0+(-2)+1=-1
} public static void myMethod() {
y=x++ + ++x; // ⑦ y = (-2) + (0)=-2 x = 0
}
}

输出:

-1

【面试题三】

class A{
final int x;
final static int y;
public A(){
y=10;
x=100; // × final变量初始化后不可重新赋值
}
{
x=100;
y=10; // × final static修饰的静态常量只能在static静态初始化块中初始化
}
}
class A{
final int x;
final static int y;
public A(){
y=10; // × final变量初始化后不可重新赋值
x=100;
}
static{
x=100; // × static静态初始化块不可调用普通变量
y=10;
}
}

【面试四】

public class Test {     // 1.准备加载类
public static Test t1 = new Test(); // 2.加载静态变量, 这里比较特殊, 静态变量引用本类的实例
// 方法块
{
System.out.println("AAA"); // 3.实例化时调用
}
// 静态代码块
static {
System.out.println("BBB"); // 4.加载静态方法
}
public static void main(String[] args) {
Test t2 = new Test(); // 5.实例化对象 -> 调用方法块
}
}

Java初始化块及执行顺序的更多相关文章

  1. 关于java中三种初始化块的执行顺序

    许多小伙伴对于java中的三种初始化块的执行顺序一直感到头疼,接下来我们就来分析一下这三种初始化块到底是怎么运行的.有些公司也会将这个问题作为笔试题目. 下面通过一段代码来看看创建对象时这么初始化块是 ...

  2. java静态初始化块的执行顺序

    先来观察下面的代码 package trr; class Root { static{ System.out.println("Root的静态初始化块"); } { System. ...

  3. java中静态初始化块的执行顺序

    在java中,其应该是先于所有的方法执行. 下面是测试代码: public class Test1 { static{ System.out.println("执行静态初始化块test1.. ...

  4. java类的初始化块/执行顺序,实例化对象数据赋值

    java里初始化一个类的对象,通过初始化快或者构造方法进行数据赋值.与其相关的执行代码有这么几种: 静态初始化块 初始化块 构造方法 静态初始化块 静态初始化块只在类加载时执行一次,同时静态初始化块只 ...

  5. 请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。

    答:执行顺序:静态初始化块->初始化块->构造函数 静态初始化块:在第一次加载类时执行,与对象的创建无关. 构造代码块:在调用构造方法时执行. 构造函数:在调用构造函数时执行.

  6. 夯实Java基础系列7:一文读懂Java 代码块和执行顺序

    目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块 ...

  7. 夯实Java基础系列7:Java 代码块和执行顺序

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  8. java静态代码块,构造方法,初始化块的执行顺序

    代码Parent和Sub进行讲解 public class Parent { private static final String name; public Parent() { System.ou ...

  9. java 代码块的执行顺序

    举一个实例程序: class HelloA { public HelloA(){ System.out.println("Hello A!父类构造方法"); } { System. ...

随机推荐

  1. python3-使用__slots__

    正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.先定义class: class Student(object): pa ...

  2. ztree 获取CheckBox选中节点时,不获取选中上级父节点

    //将第三个参数改为false,表示不去勾选父节点下的所有子节点 zTreeObj.checkNode(node, true, false); setting.check.chkboxType = { ...

  3. bzoj4764 弹飞大爷 LCT

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4764 题解 如果 \(a_i > 0\) 的话,那么就是 bzoj2002 的原题.直接 ...

  4. Pool数据池

    sql相关请点我!!! 1.普通的sql语句查询完成之后,就要断开,下次查的时候又要重新开启,这样的话,效率会很低,所以利用pool 数据池来解决这种问题,pool数据池查询完之后,就不用去重新链接数 ...

  5. ESP8266-利用网页控制ESP8266

    说明:发出/gpio/1   就输出 "亮灯":   /gpio/0  就输出 "灭灯"  #include <ESP8266WiFi.h> con ...

  6. MySQL数据库4Python操作mysql、索引、慢查询日志

    目录 一.Python 操作 mysql 1.1python 操作 mysql 1.2查询数据 1.3增加(添加.更新)数据 1.4修改数据 1.5删除数据 1.6SQL注入问题 1.6.1问题的引入 ...

  7. 认识js数组

    1.认识数组 数组就是某类数据的集合,数据类型可以是整型.字符串.甚至是对象Javascript不支持多维数组,但是因为数组里面可以包含对象(数组也是一个对象),所以数组可以通过相互嵌套实现类似多维数 ...

  8. Qt 中文问题

    Qt windows/linux跨平台中文编码解决 系统环境:windows8.1 / ubuntu 14.04Qt5.4.2 QtCreator 3.4.1 编码设置:QtCreator:工具/选项 ...

  9. Spring Cloud架构教程 (四)服务网关(路由配置)

    传统路由配置 所谓的传统路由配置方式就是在不依赖于服务发现机制的情况下,通过在配置文件中具体指定每个路由表达式与服务实例的映射关系来实现API网关对外部请求的路由. 没有Eureka和Consul的服 ...

  10. java 中创建线程有哪几种方式?

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行 ...