Java面向对象之初始化块

在程序设计中,让数据域正确地执行初始化一直是一个亘古不变的真理。

那么,有哪些手段可以初始化数据域呢:

  • 在构造器中设置值。
  • 在声明中赋值。
  • 使用初始化块

本篇探讨关于Java中的初始化块的注意点:Java中的初始化块是类中的一种成员,但是既没有名字,也没有标识,不能够被调用,它仅仅只是在创建Java对象时隐式执行初始化。

普通初始化块

  • 普通的初始化块就是非static修饰的。

  • 声明时以花括号{}包起代码,被包住的就是初始化代码,整体就是一个初始化块。

  • 可以有很多个初始化块,按顺序先后且全部地执行,所以没什么必要分开,一起就完事。

  • 声明实例变量时指定默认值普通初始化块都被看做是对象的初始化代码,按先后顺序执行。

  • 初始化块总是在构造器之前被调用

  • 如果多个重载的构造器有相同且与传入形参无关的语句可以一起提入初始化块。

public class NormalBlock {
int a = 5;
{
// a = 6;
System.out.println("初始化块之后的a为"+a);
}
// {
// int a = 8;
// System.out.println("初始化块中重新定义了一个a?"+a);
// }
NormalBlock(){ System.out.println("构造器中赋a的值为"+a);
}
}
class NormalTest{
public static void main(String[] args) {
new NormalBlock();
}
}
  • 上面注释语句时,结果如下:
初始化块之后的a为5
构造器中赋a的值为5

可以看到,在这个例子中,声明实例变量指定默认值也被看作初始化代码,且依次执行,先初始化块,后构造器。(可以试着调换它们的位置验证一下哈)

  • 上面解除注释语句之后,我对结果是产生疑惑的:
初始化块之后的a为6
初始化块中重新定义了一个a?8
构造器中赋a的值为6

我的疑惑点在于,我一开始以为,我在第二个代码块中定义的和之前同名的变量a是同一个(然而并不是)这样也就算了,初始化代码之后,执行构造器时,调用了a,那么这时这个a调用的是哪个呢,于是产生疑惑,希望知道的小伙伴可以为我指点迷津

  • 我在测试的时候还遇到了ilegal forward reference,即前向引用错误,如下图。
    {
age = 50;
if(age>40) System.out.println("Father类的初始化块且age>40");
System.out.println("Father类的第一个初始化块");
}
int age =20;

产生原因:是因为在还没有定义该变量时,就引用了它,所以为了避免这样的错误,尽量将初始化块放在成员变量声明之后。

静态初始化块

和普通的对应的就是静态初始化块啦,也就是用static修饰的,也称为类初始化块。根据名称分析,类初始化块负责对类进行初始化,而普通初始化块负责对对象执行初始化。

  • static{}的格式包围对类变量的初始化。
  • 由于静态初始化块和类相关,负责对类进行初始化,所以总是比普通初始化块先执行。
  • 通常用于对类变量执行初始化处理,而不能对实例变量进行初始化处理。
  • 静态初始化块属于类的静态成员,遵循静态成员不能访问非静态成员的规则:即不能访问非静态成员(实例变量和实例方法)
  • 类似地,静态初始化块声明静态成员变量时指定初始值都时该类的初始化代码。

初始化块与构造器

关于初始化块与构造器的先后调用顺序,结合代码来理解一下子。

package com.my.pac17;

/**
* @auther Summerday
*/
public class A {
{
System.out.println("A.instance initializer");
}
static {
System.out.println("A.static initializer");
}
public A() {
System.out.println("A.A");
}
}
class B extends A {
{
System.out.println("B.instance initializer");
}
static {
System.out.println("B.static initializer");
}
public B() {
System.out.println("B.B");
}
public B(String m) {
this();
System.out.println("B.B," + m);
}
}
class C extends B {
{
System.out.println("C.instance initializer");
}
static {
System.out.println("C.static initializer");
}
public C() {
super("ccc");
System.out.println("C.C");
}
}
class BTest {
public static void main(String[] args) {
new C();
System.out.println("*******");
new C();
}
}
/*测试结果*/
A.static initializer
B.static initializer
C.static initializer
/*类初始化阶段,限制性最顶层父类的静态初始化块
然后依次向下,直到执行当前类的静态初始化块*/
A.instance initializer
A.A
B.instance initializer
B.B//调用B的无参构造器
B.B,ccc//调用B的带参构造器
C.instance initializer//最后执行C
C.C
/*对象初始化阶段,先执行最顶层父类的初始化块,
最顶层父类的构造器,然后依次向下,直到执行当前
类的初始化块、当前类的构造器*/
*******
//不用执行静态初始化语句
A.instance initializer
A.A
B.instance initializer
B.B
B.B,ccc
C.instance initializer
C.C
  • static修饰的静态初始化块,总是先被调用,且在继承关系中,最早的父类中的静态初始化块先执行。
  • 可以看到,第二次创建子类对象时,就没有再执行静态初始化块中的初始化,因为三个类已经加载成功
  • 普通初始化块和构造器的执行顺序为,普通初始化块在构造器之前执行,从最早的父类一直到当前类。

Java面向对象之初始化块的更多相关文章

  1. 浅谈Java中静态初始化块跟非初始化块

    众所周知在JAVA编程语言中有两种初始化块:   静态初始化块 非静态初始化块 他们到底有什么区别呢?今天就浅谈一下JAVA中静态初始化块和非静态初始化块的区别   静态初始化块 定义:       ...

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

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

  3. java中的初始化块

    public class Person { int a=6;//声明实例变量制定默认值,也可以认为是对象的初始化代码,执行顺序与源代码中的排列顺序相同 { System.out.println(&qu ...

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

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

  5. java面向对象---对象初始化

    在本地变量中,如果定义了一个变量后没有赋值就使用,那么eclipse就会报错:但是在成员变量中,java是会强制给一个没有初始化的变量一个默认的初始值0, 如果是一个boolean类型的变量,那么默认 ...

  6. 什么是Java实例初始化块

    在本篇文章,我将会使用一个例子展示什么是实例变量初始化块,实例初始化块和静态初始化块,然后说明在Java中实例初始化块是如何工作的. 执行顺序 查看下面的代码,你知道哪个先执行吗? package s ...

  7. java 面向对象 — 类和对象

    构造方法 1.构造器必须与类同名(如果一个源文件中有多个类,那么构造器必须与公共类同名) 2.每个类可以有一个以上的构造器 3.构造器可以有0个.1个或1个以上的参数 4.构造器没有返回值 5.构造器 ...

  8. 8、java高级面向对象-重载、构造器重载、初始化块、this、super、对象构造和初始化分析、覆盖、toString

    1.方法的重载(overload) 同一个类中同时存在一个以上的同名函数,参数个数或类型不同或顺序不同,称为方法的重载. 和返回值无关! 构造器重载:非默认构造器和默认构造器其实就是方法的重载. 2. ...

  9. Java的初始化块、静态初始化块、构造函数的执行顺序及用途探究

    Java与C++有一个不同之处在于,Java不但有构造函数,还有一个”初始化块“(Initialization Block)的概念.下面探究一下它的执行顺序与可能的用途. 执行顺序 首先定义A, B, ...

随机推荐

  1. windows版的mysql主从复制环境搭建

    背景 最近在学习用Spring Aop来实现数据库读写分离的功能. 在编写代码之前,首先是要部署好mysql的环境,因为要实现读写分离,所以至少需要部署两个mysql实例,一主一从,并且主从实例之间能 ...

  2. Oracle数据库 获取CLOB字段存储的xml格式字符串指定节点的值

    参照: Oracle存储过程中使用游标来批量解析CLOB字段里面的xml字符串 背景:在写存储过程时,需要获取表单提交的信息.表单信息是以xml格式的字符串存储在colb类型的字段dataxml中,如 ...

  3. Alibaba Nacos 学习(四):Nacos Docker

    Alibaba Nacos 学习(一):Nacos介绍与安装 Alibaba Nacos 学习(二):Spring Cloud Nacos Config Alibaba Nacos 学习(三):Spr ...

  4. PHP编程20大效率要点

    1.如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍. 2.$row[’id’] 的速度是$row[id]的7倍. 3.echo 比 print 快,并且使用ech ...

  5. 【2018寒假集训 Day2】【动态规划】抢金块

    抢金块 输入文件:gold.in 输出文件:gold.out 问题描述: 地面上有一些格子,每个格子上面都有金块,但不同格子上的金块有不同的价值,你一次可以跳S至T步 .如果S=2,T=4.你就可以跳 ...

  6. 图解 Spring:HTTP 请求的处理流程与机制【1】

    2003 年,老兵哥初到中兴开始研究生实习,Spring 就是那年诞生的,2004 年 3 月发布了 1.0 版本,到现在已经超过 15 年了.从单体式分层架构到云原生微服务架构,它稳坐在 JAVA ...

  7. selenium常用命令之操作页面元素及获取元素内容的事件整理

    /**id <input type="text" id="phone" name="phone" class="LoginT ...

  8. 复制节点(cloneNode)

    DOM提供用来复制节点方法. cloneNode():将为给定节点创建一个副本,这个方法的返回值是一个指向新建克隆节点的引用指针, reference = node.cloneNode(deep) 这 ...

  9. P1307 数字反转

    题目描述 给定一个整数,请将该数各个位上数字反转得到一个新数.新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(参见样例2). 输入输出格式 输入格式: 一个 ...

  10. AutoCAD二次开发(2020版)--4,使用ARX向导创建编程模板(框架)--

    手动创建ObjectARX应用程序非常麻烦,在此步骤中,将介绍ObjectARX向导. 在这里,我们将使用ObjectARX向导创建我们的ObjectARX应用程序. 本节的程序的需求是,接收CAD用 ...