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

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

  1. public class Demo01 {
  2. public int a1 = 1;
  3. public String a2 = "initiaied!";
  4.  
  5. public Demo01() {
  6. System.out.println(a1);
  7. System.out.println(a2);
  8. System.out.println("构造器方法被执行");
  9. }
  10.  
  11. public static void main(String[] args) {
  12. Demo01 demo01 = new Demo01();
  13. }
  14. }
  15.  
  16. 运行结果:
  17. 1
  18. initiaied!
  19. 构造器方法被执行

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

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

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

  1. public class Demo02 {
  2. public Cup cup1 = new Cup(1);
  3. public static Cup cup2 = new Cup(2);
  4.  
  5. public Demo02() {
  6. System.out.println("Demo02构造器被执行!");
  7. }
  8.  
  9. public static void main(String[] args) {
  10. Demo02 demo02 = new Demo02();
  11. Demo02 demo02_01 = new Demo02();
  12. }
  13. }
  14.  
  15. class Cup {
  16. public Cup(int i) {
  17. System.out.println("Cup->" + i);
  18. }
  19. }
  20.  
  21. 运行结果:
  22. Cup->2
  23. Cup->1
  24. Demo02构造器被执行!
  25. Cup->1
  26. Demo02构造器被执行

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

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

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

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

  1. public class Demo03 {
  2. static Table table1;
  3. Table table2;
  4.  
  5. static {
  6. table1 = new Table(1);
  7. }
  8.  
  9. {
  10. table2 = new Table(2);
  11. }
  12.  
  13. public Demo03() {
  14. System.out.println("Demo03构造器被执行");
  15. }
  16.  
  17. public static void main(String[] args) {
  18. new Demo03();
  19. }
  20. }
  21.  
  22. class Table {
  23. public Table(int i) {
  24. System.out.println("Table->" + i);
  25. }
  26. }
  27.  
  28. 运行结果:
  29. Table->1
  30. Table->2
  31. Demo03构造器被执行

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

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

  1. public class Demo04 extends Insect {
  2. private int k = fun("Demo04中的k被初始化");
  3. private static int x2 = fun("Demo04中的x2被初始化");
  4.  
  5. public Demo04() {
  6. System.out.println("k=" + k);
  7. System.out.println("j=" + j);
  8. }
  9.  
  10. public static void main(String[] args) {
  11. Demo04 demo04 = new Demo04();
  12. }
  13. }
  14.  
  15. class Insect {
  16. public int i = 9;
  17. public int j;
  18. public static int x1 = fun("Insect中的x1被初始化");
  19.  
  20. public Insect() {
  21. System.out.println("i=" + i + ",j=" + j);
  22. j = 39;
  23. }
  24.  
  25. public static int fun(String s) {
  26. System.out.println(s);
  27. return 47;
  28. }
  29. }
  30. 运行结果:
  31. Insect中的x1被初始化
  32. Demo04中的x2被初始化
  33. i=9,j=0
  34. Demo04中的k被初始化
  35. k=47
  36. j=39

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

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

五、总结

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

  1. public class Son extends Father {
  2. int m = fun("Son中的m 被初始化");
  3.  
  4. public Son() {
  5. System.out.println("m = " + m);
  6. System.out.println("j = " + j);
  7. }
  8.  
  9. public static int x3 = fun("Son中的x3 被初始化");
  10.  
  11. public static void main(String[] args) {
  12. Son son = new Son();
  13. }
  14. }
  15.  
  16. class Father extends GrandFather {
  17.  
  18. public int k = fun("Father中的k被初始化");
  19. public static int x2 = fun("Father中的x2被初始化");
  20.  
  21. public Father() {
  22. System.out.println("k=" + k);
  23. System.out.println("j=" + j);
  24. }
  25. }
  26.  
  27. class GrandFather {
  28. public int i = 9;
  29. public int j;
  30. public static int x1 = fun("GrandFather中的x1被初始化");
  31.  
  32. public GrandFather() {
  33. System.out.println("i=" + i + ",j=" + j);
  34. j = 39;
  35. }
  36.  
  37. public static int fun(String s) {
  38. System.out.println(s);
  39. return 47;
  40. }
  41. }
  42. 运行结果:
  43. GrandFather中的x1被初始化
  44. Father中的x2被初始化
  45. Son中的x3 被初始化
  46. i=9,j=0
  47. Father中的k被初始化
  48. k=47
  49. j=39
  50. Son中的m 被初始化
  51. m = 47
  52. 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. Java-Java8特性(更新中)

    Java8新特性 之前零零散散写了很多java8的内容,今天做一个整理,也算是整理用到的内容,当然细化的话还有很多,只是说暂时用不到,为了面试的话已经够了 日期计算 Lambda表达式 函数式接口(比 ...

  2. el-upload上传列表实现 展开 收起

    # el-upload上传列表实现 展开 收起 #### 无图言*,所以先上最终效果图(想参考代码的可以直接滑到最后) ### 具体实现思路 注意: 每个人的项目环境以及需求,都不尽相同,所以这里仅仅 ...

  3. JS replace 替换全部数据

    (1)使用具有全局标志g的正则表达式 var str = "dogdogdog"; var str2 = str.replace(/dog/g,"cat");/ ...

  4. Linux系统下安装NodeJS

    下载NodeJS二进制压缩包 去NodeJS官网https://nodejs.org/zh-cn/,下载二进制压缩包,进入下载页面之后你将看到很多下载选项: 源码不包含bin目录,不是可运行的应用程序 ...

  5. js--你需要知道的字符串使用方法(含es6及之后)

    前言 字符串作为 JavScript 的基本数据类型,在开发以及面试过程中作为程序员对基础掌握情况的重要考点,本文来总结一下字符串的相关属性以及用法.包含了ES6中的一些新语法特性. 正文 1.字符串 ...

  6. 跨域解决之JSONP和CORS的详细介绍

    JSONP跨域和CORS跨域 什么是跨域? 跨域:指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的,是浏览器的安全限制! 同源策略 同源策略:域名.协议.端口均相同. 浏览器执行Jav ...

  7. ESP32构建系统(CMake版)

    ESP32 芯片是一款 2.4 GHz Wi-Fi 和蓝牙双模芯片,内置 1 或 2 个 32 位处理器,运算能力最高可达 600 DMIPS. ESP-IDF 即乐鑫物联网开发框架,可为在 Wind ...

  8. MySQL 那些常见的错误设计规范

    依托于互联网的发达,我们可以随时随地利用一些等车或坐地铁的碎片时间学习以及了解资讯.同时发达的互联网也方便人们能够快速分享自己的知识,与相同爱好和需求的朋友们一起共同讨论. 但是过于方便的分享也让知识 ...

  9. fastjson: json对象,json对象数组,javabean对象,json字符串之间的相互转化

    fastjson: json对象,json对象数组,javabean对象,json字符串之间的相互转化 在开发过程中,经常需要和前端交互数据,数据交互的格式都是JSON,在此过程中免不了json字符串 ...

  10. QT. 学习之路 一

    初识QT 一:   hello-world: #include "mainwindow.h" #include <QApplication> #include < ...