一、变量与构造器的初始化顺序

我们知道一个类中具有类变量、类方法和构造器(方法中的局部变量不讨论,他们是在方法调用时才被初始化),当我们初始化创建一个类对象时,其初始化的顺序为:先初始化类变量,再执行构造器方法。代码验证:

public class Demo01 {
public int a1 = 1;
public String a2 = "initiaied!"; public Demo01() {
System.out.println(a1);
System.out.println(a2);
System.out.println("构造器方法被执行");
} public static void main(String[] args) {
Demo01 demo01 = new Demo01();
}
} 运行结果:
1
initiaied!
构造器方法被执行

可以看出,当我们创建一个Demo01对象时,先初始化了变量a1和a2,然后执行构造器方法。

二、静态变量与非静态变量的初始化顺序

静态变量是属于类本身,无论创建多少个对象,静态变量都只有一份存储区域,因此他会在类首次被访问或者首次创建类对象时被初始化,而且有且只能初始化一次。而非静态变量是属于每个对象,他是在创建每个对象时都初始化一次。因此,静态变量要先于非静态进行初始化。例子:

public class Demo02 {
public Cup cup1 = new Cup(1);
public static Cup cup2 = new Cup(2); public Demo02() {
System.out.println("Demo02构造器被执行!");
} public static void main(String[] args) {
Demo02 demo02 = new Demo02();
Demo02 demo02_01 = new Demo02();
}
} class Cup {
public Cup(int i) {
System.out.println("Cup->" + i);
}
} 运行结果:
Cup->2
Cup->1
Demo02构造器被执行!
Cup->1
Demo02构造器被执行

当程序要执行main方法时,会先加载Demo02类文件,在加载时就会先初始化静态变量cup2,因此控制台输出"cup->2"。类加载完后,开始执行main方法,创建demo02对象,这时就会初始化类中的非静态变量cup1,控制台输出"cup->1",然后执行构造器方法。创建第二个对象时,只初始化cup1,cup2为静态变量只初始化一次。

三、静态代码块与非静态代码块

静态代码块本质上就是一段静态变量的代码,其初始化和静态变量没有区别:当类首次被访问或者首次创建该类对象时被初始化,并且只初始化一次。

非静态代码块就是一段非静态变量的代码,他和非静态变量的初始化没有区别。

public class Demo03 {
static Table table1;
Table table2; static {
table1 = new Table(1);
} {
table2 = new Table(2);
} public Demo03() {
System.out.println("Demo03构造器被执行");
} public static void main(String[] args) {
new Demo03();
}
} class Table {
public Table(int i) {
System.out.println("Table->" + i);
}
} 运行结果:
Table->1
Table->2
Demo03构造器被执行

四、父类与子类的初始化顺序

没有父类就没有子类,因此无论是类加载还是创建实例对象,父类都优先于子类进行初始化。

public class Demo04 extends Insect {
private int k = fun("Demo04中的k被初始化");
private static int x2 = fun("Demo04中的x2被初始化"); public Demo04() {
System.out.println("k=" + k);
System.out.println("j=" + j);
} public static void main(String[] args) {
Demo04 demo04 = new Demo04();
}
} class Insect {
public int i = 9;
public int j;
public static int x1 = fun("Insect中的x1被初始化"); public Insect() {
System.out.println("i=" + i + ",j=" + j);
j = 39;
} public static int fun(String s) {
System.out.println(s);
return 47;
}
}
运行结果:
Insect中的x1被初始化
Demo04中的x2被初始化
i=9,j=0
Demo04中的k被初始化
k=47
j=39

当执行main方法时,加载器开始加载Demo04类文件,在加载过程中,加载器会注意到他有一个父类Insect还没被加载,因此会先加载父类Insect文件。类加载过程中会完成静态变量的初始化(此时并不执行构造器方法,构造器方法只有在创建对象时调用),Insect类加载完成后,接着加载Demo04类,都加载完成后,就开始执行main方法中的代码,创建Demo04对象。

由于继承关系,因此先创建父类Insect的实例对象,因此父类中的变量初始化和构造器先被执行,然后在初始化子类Demo04中的非静态变量和执行构造器方法。

五、总结

最后放一段代码,把前面所说情况都放在一起。

public class Son extends Father {
int m = fun("Son中的m 被初始化"); public Son() {
System.out.println("m = " + m);
System.out.println("j = " + j);
} public static int x3 = fun("Son中的x3 被初始化"); public static void main(String[] args) {
Son son = new Son();
}
} class Father extends GrandFather { public int k = fun("Father中的k被初始化");
public static int x2 = fun("Father中的x2被初始化"); public Father() {
System.out.println("k=" + k);
System.out.println("j=" + j);
}
} class GrandFather {
public int i = 9;
public int j;
public static int x1 = fun("GrandFather中的x1被初始化"); public GrandFather() {
System.out.println("i=" + i + ",j=" + j);
j = 39;
} public static int fun(String s) {
System.out.println(s);
return 47;
}
}
运行结果:
GrandFather中的x1被初始化
Father中的x2被初始化
Son中的x3 被初始化
i=9,j=0
Father中的k被初始化
k=47
j=39
Son中的m 被初始化
m = 47
j = 39

浅谈Java类中的变量初始化顺序的更多相关文章

  1. java类中成员的初始化顺序(一)

    类被创建之后的成员的初始化顺序到底是怎么样的? 首先 不考虑继承 package com; public class DemoOne { /** * 关于类的初始化顺序 */ //不考虑继承结构的情况 ...

  2. 浅谈java类集框架和数据结构(2)

    继续上一篇浅谈java类集框架和数据结构(1)的内容 上一篇博文简介了java类集框架几大常见集合框架,这一篇博文主要分析一些接口特性以及性能优化. 一:List接口 List是最常见的数据结构了,主 ...

  3. Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序

    先看一道Java面试题: public class Baset { private String baseName = "base"; // 构造方法 public Baset() ...

  4. 浅谈JAVA GUI中,AWT与Swing的区别、联系及优缺点

    浅谈JAVA GUI中,AWT与Swing的区别.联系及优缺点 A.区别 1.发布的时间 AWT是在JDK 1.0版本时提出的 Swing是在AWT之后提出的(JAVA 2) 2. ”重量” AWT是 ...

  5. 【基础】java类的各种成员初始化顺序

    父子类继承时的静态代码块,普通代码块,静态方法,构造方法,等先后顺序 前言: 普通代码块:在方法或语句中出现的{}就称为普通代码块.普通代码块和一般的语句执行顺序由他们在代码中出现的次序决定--“先出 ...

  6. 在java中浅谈Math类中的常用方法

    通过最近的学习,学到了一些的Math类中的常见方法 package org.stm.demo; public class Test { public static void main(String[] ...

  7. 分析java类的静态成员变量初始化先于非静态成员变量

    依上图中当class字节码文件被jvm虚拟机加载到内存中依次经过 连接 验证:对字节码进行验证 准备:给静态变量分配内存并赋予变量类型各自的默认值(注:基本类型为0或false,对象为null,sta ...

  8. 浅谈java类集框架和数据结构(1)

    在另外一篇博客我简单介绍了java类集框架相关代码和理论. 这一篇博客我主要分析一下各个类集框架的原理以及源码分析. 一:先谈谈LinkedList 这是LinkedList源码的开头,我们能看到几点 ...

  9. Java类中代码的执行顺序 静态代码块>构造代码块>构造方法

    一:静态代码块 注意是代码块,不是静态函数.函数要调用才执行,代码块加载就执行,一般是静态变量的声明与初始化.被static修饰的代码块(赋值.输出操作等).类中静态语句块仅在类加载时被执行一次 如 ...

随机推荐

  1. 『心善渊』Selenium3.0基础 — 2、Selenium测试框架环境搭建(Windows)

    目录 1.浏览器安装 2.浏览器驱动下载 (1)ChromeDriver for Chrome (2)Geckodriver for Firefox (3)IEDriverServer for IE ...

  2. 『无为则无心』Python基础 — 5、Python开发工具的安装与使用

    目录 1.Pycharm下载 2.Pycharm安装 3.PyCharm界面介绍 4.基本使用 (1)新建Python项目 (2)编写Python代码 (3)执行代码查看结果 (4)设置PyCharm ...

  3. CosId 1.0.0 发布,通用、灵活、高性能的分布式 ID 生成器

    CosId 通用.灵活.高性能的分布式 ID 生成器 介绍 CosId 旨在提供通用.灵活.高性能的分布式系统 ID 生成器. 目前提供了俩大类 ID 生成器:SnowflakeId (单机 TPS ...

  4. Spring学习日记01_IOC_xml的三种注入方式

    什么是IOC 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理 使用IOC目的:为了耦合度降低 做入门案例就是IOC实现 IOC底层原理 xml解析 工厂模式 反射 原始方式 cla ...

  5. Spring Cloud 整合 Feign 的原理

    前言 在 上篇 介绍了 Feign 的核心实现原理,在文末也提到了会再介绍其和 Spring Cloud 的整合原理,Spring 具有很强的扩展性,会把一些常用的解决方案通过 starter 的方式 ...

  6. 乘风破浪,Windows11预览版升级和安装,积极准备中的大跃进

    安装Windows11 暂时官方还没出可靠的ISO 升级到Windows11 预览版 关于一些限制 目前DEV预览通道对从老系统升级到Windows11暂时没有什么限制,只是会提示你可能不太好,但是安 ...

  7. 让你发布的nuget包支持源代码调试

    前情概要 在不久的从前(也还是要以年为单位哈), 我们如果需要调试第三方代码, 或者框架代码很麻烦. 需要配置symbols, 匹配原始代码路径等. 为此, MS推出了 Source Link 功能, ...

  8. Python迭代器和生成器你学会了吗?

    在了解什么是迭代器和生成器之前,我们先来了解一下容器的概念.对于一切皆对象来说,容器就是对象的集合.例如列表.元祖.字典等等都是容器.对于容器,你可以很直观地想象成多个元素在一起的单元:而不同容器的区 ...

  9. AcWing 99. 激光炸弹

    地图上有n个目标,用整数x,y表示目标在地图上的位置,每个目标都有一个价值Wi. 注意:不同目标可能在同一位置. 现在有一种新型的激光炸弹,可以摧毁一个包含r个位置的正方形内的所有目标. 激光炸弹的投 ...

  10. Redis的内存回收原理,及内存过期淘汰策略详解

    Redis 内存回收机制Redis 的内存回收主要围绕以下两个方面: 1.Redis 过期策略:删除过期时间的 key 值 2.Redis 淘汰策略:内存使用到达 maxmemory 上限时触发内存淘 ...