Java初始化块及执行顺序
- 理解
初始化块又称为代码块。属于类中的第四大成员。本质上是一个方法,它也有方法体,但没有方法名,没有参数,没有返回,而且也不是通过对象或类名显式调用,而是通过隐式调用
是构造器的补充
语法
[修饰符]{
方法体
}
注意:
①修饰符只能是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初始化块及执行顺序的更多相关文章
- 关于java中三种初始化块的执行顺序
许多小伙伴对于java中的三种初始化块的执行顺序一直感到头疼,接下来我们就来分析一下这三种初始化块到底是怎么运行的.有些公司也会将这个问题作为笔试题目. 下面通过一段代码来看看创建对象时这么初始化块是 ...
- java静态初始化块的执行顺序
先来观察下面的代码 package trr; class Root { static{ System.out.println("Root的静态初始化块"); } { System. ...
- java中静态初始化块的执行顺序
在java中,其应该是先于所有的方法执行. 下面是测试代码: public class Test1 { static{ System.out.println("执行静态初始化块test1.. ...
- java类的初始化块/执行顺序,实例化对象数据赋值
java里初始化一个类的对象,通过初始化快或者构造方法进行数据赋值.与其相关的执行代码有这么几种: 静态初始化块 初始化块 构造方法 静态初始化块 静态初始化块只在类加载时执行一次,同时静态初始化块只 ...
- 请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。
答:执行顺序:静态初始化块->初始化块->构造函数 静态初始化块:在第一次加载类时执行,与对象的创建无关. 构造代码块:在调用构造方法时执行. 构造函数:在调用构造函数时执行.
- 夯实Java基础系列7:一文读懂Java 代码块和执行顺序
目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块 ...
- 夯实Java基础系列7:Java 代码块和执行顺序
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- java静态代码块,构造方法,初始化块的执行顺序
代码Parent和Sub进行讲解 public class Parent { private static final String name; public Parent() { System.ou ...
- java 代码块的执行顺序
举一个实例程序: class HelloA { public HelloA(){ System.out.println("Hello A!父类构造方法"); } { System. ...
随机推荐
- maven 依赖显示红线 pom文件不显示红线的一种可能问题
pom文件引用的是CDH的jar包 而没有配置CDH的仓库 导致maven找不到资源 ,依赖显示红色波浪,并且在仓库内生成了一堆.lastupdate文件 解决: 1. 删除本地仓库内所有的.las ...
- App 区别
本文的结构主要分为以下部分: 1.app的分类 2.每类app的定义,明确各类app具体是什么 3.各类app的优缺点 4.具体开发过程中,到底该采用哪种类型的app 1.app的分类 大致可以分为这 ...
- 【leetcode】1123. Lowest Common Ancestor of Deepest Leaves
题目如下: Given a rooted binary tree, return the lowest common ancestor of its deepest leaves. Recall th ...
- BZOJ 5129: [Lydsy1712月赛]树上传送 点分树+Dijkstra
Description http://www.lydsy.com/JudgeOnline/upload/201712/prob12.pdf Input Output 暑假集训的时候点分树做的比较少,所 ...
- 【bzoj3195】【 [Jxoi2012]奇怪的道路】另类压缩的状压dp好题
(上不了p站我要死了) 啊啊,其实想清楚了还是挺简单的. Description 小宇从历史书上了解到一个古老的文明.这个文明在各个方面高度发达,交通方面也不例外.考古学家已经知道,这个文明在全盛时期 ...
- 【CF10D】LCIS(LCIS)
题意:求两个序列的LCIS n,m<=300,a[i]<=1e9 题意:O(n^2) O(n^3)的话设dp[i,j]为A终点为a[1..i]且B终点为b[j]的最大长度,分a[i]==b ...
- 给字体和元素加阴影text-shadow和box-shadow
1.语法: 对象选择器 {text-shadow:X轴偏移量 Y轴偏移量 阴影模糊半径 阴影颜色} 注:text-shadow可以使用一个或多个投影,如果使用多个投影时必须需要用逗号“,”分开. 2 ...
- angular项目开发
第 1 步:安装 Angular CLI 你可以使用 Angular CLI 来创建项目.生成应用和库代码,以及执行各种持续开发任务,比如测试.打包和部署. 全局安装 Angular CLI. 要使用 ...
- SourceTree跳过初始设置
转载https://www.cnblogs.com/xiofee/p/sourcetree_pass_initialization_setup.html 如何跳过初始设置,只需要在安装路径中添加一个a ...
- python开发环境准备
python 以版本众多,包之间依赖复杂而著称,所以一个趁手的开发环境还是很有必要的. 我的建议是用Anaconda做环境隔离.包管理,PyCharm做项目开发,jupyter做笔记,ipython和 ...