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

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

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. JUL 日志框架

    1.JUL 简介 JUL 全称 Java Util Logging,位于java.util.logging.Logger 包.它是 java 原生的日志框架,使用时无需另外引用第三方的类库,相对其他的 ...

  2. 10.8、mysql日志

    mysql生成或相关联的日志文件种类繁多,这里重点关注与mysql数据库服务相关 的几类日志文件: 1.错误日志: 记录mysql服务进程mysql的在启动/关闭/运行过程中遇到的错误信息: [mys ...

  3. python之字典(dict)基础篇

    字典:dict 特点: 1>,可变容器模型,且可存储任意类型对象,字符串,列表,元组,集合均可: 2>,以key-value形式存在,每个键值 用冒号 : 分割,每个键值对之间用逗号 , ...

  4. Linux安装telnet(转)

      一.安装telnet 1.检测telnet-server的rpm包是否安装 [root@localhost ~]# rpm -qa telnet-server 若无输入内容,则表示没有安装.出于安 ...

  5. java封装继承以及多态(含代码)

    封装 该露的露,该藏的藏 我们常需设计要追求,"高内聚,低耦合".高内聚就是类的内部数据操作细节自己完成.不允许外部干涉:低耦合:仅暴漏少量的方法给外部使用. 封装(数据的隐藏) ...

  6. 使用VS远程调试其他电脑上安装的软件

    今天在用户的一台机器上遇到了很奇怪的问题.一个按钮点击时概率性的第一次点击无反馈. 因为是概率性的,概率又很低,而当初在设计Log时又设计的是必须重启软件才会生效log开关: 所以这里使用当时rele ...

  7. Linux | 浏览(切换)目录命令

    例出目录和文件 --> ls ls 命令是最常用的 Linux 命令之一,ls 是 list 的缩写,表示:列出 在 Linux 中 ls 命令用于列出文件和目录 一些常用的参数 ls -a # ...

  8. 基于腾讯云Serverless的HTTP服务探活函数

    本文基于 Golang 开发了一款简单易用的拨测云函数,入口函数与腾讯云 Serverless SDK 绑定.与目前腾讯云中默认的拨测函数不同的是, url-tester-func 支持非 200 响 ...

  9. ArrayList 从源码角度剖析底层原理

    本篇文章已放到 Github github.com/sh-blog 仓库中,里面对我写的所有文章都做了分类,更加方便阅读.同时也会发布一些职位信息,持续更新中,欢迎 Star 对于 ArrayList ...

  10. C语言:常用数学函数

    #include <stdio.h> #include <math.h> #include <stdlib.h> #include <time.h> # ...