深入分析Java对象的建构顺序

android OTA升级之后,apk崩溃无法启动 也就是说,我们这个高低版本是fingerprint相同的情况,这个问题追述到jenkins编译,启动job时会初始化一个BUILD_NUMBER值,这个值正好跟Android的build系统的名称重复,这就导致Android build系统那一套拼接时间戳的值不会走,因为jenkins一启动就会定义该值,而我们jenkins服务器迁移过,这个值又会从1开始累计,导致前后版本都是16,从而导致fingerprint一致。问题背景:系统版本从低版本升级到高版本后,apk崩溃启动失败。硬件平台:QCS6125。 阅读详情

对于下面的代码,许多有经验的程序员都没能给出正确的答案。如果你能只看代码给出的答案和文章末尾出给出大答案一致,那么你已经掌握了Java对象的建构顺序,中间的分析可以不用看了。

复制代码
 1 /**
 2  * 父类Foo,实现控制台输出
 3  *
 4  * @author youngto
 5  * @since 2013-01-25
 6  */
 7 class Foo {
 8 
 9     private int index = 100;
10     
11     //静态代码块
12     static {        
13         System.out.println("Foo static");
14     }
15     
16     //初始化代码块
17     {        
18         System.out.println("Foo initialization");
19     }
20     
21     public Foo() {
22         System.out.println("Foo constructor");
23         System.out.println(printIndex());
24     }
25     
26     protected int printIndex() {
27         return index;
28     }
29     
30 }
31 
32 /**
33  * 子类Bar,实现控制台输出
34  *
35  * @author youngto
36  * @since 2013-01-25
37  */
38 public class Bar extends Foo{
39     
40     private int index = 100;
41     static Bar bar = new Bar();
42     
43     //静态代码块
44     static{
45         System.out.println("Bar static");
46     }
47     
48     //初始化代码块
49     {
50         System.out.println("Bar initialization");
51     }
52     
53     public Bar() {
54        System.out.println("Bar constructor");
55        System.out.println(printIndex());
56     }
57     
58     @Override
59     protected int printIndex() {
60         System.out.println(bar);
61         return index;
62     }
63     
64     public static void main(String[] args) {
65         Foo foo = new Bar();
66         System.out.println(foo.printIndex());
67         foo = new Bar();
68     }
69 
70 }
复制代码

 

 在对象建构过程中。为确保其正确性,以下事件一定会以固定顺序发生:

a、heap之中分配内存,用以存放全部的 instance 变量以及这个对象连同其 superclasses的实现专属数据(implementation-specific data)。所谓「实现专属数据」包括指向“class and method data的指针。

b、 对象的Instance变量被初始化为其相应的缺省值。

c、调用most derived class(最深层派生类)的构造函数(constructor)(注:事实上,构造函数被.class文件中的一个initialization method(初始化函数)替换了。Initialization method是名为<init>的特殊函数,由Java编译器安放在.class文件里。其中包含[构造函数代码]、[instance变量之初始化代码],以及[调用superclass Initialization method]之代码。)。构造函致做的第一件事就是调用superclass的构造函数。这个程序一直反复持续到 java.lang.object构适函数被调用为止。一定要记住,java.lang.object是一切java对象的base class。

d、所有对象的静态代码块或静态字段先获得执行,优先级从父类开始。

e、在构造函数本体执行之前,所有 instance 变量的初值设定式(initializers)和初始化区(initialization blocks)先获得执行,然后才执行构造函数本体。于是base class的构造函数最先执行,most derived class的构造函数最后执行。这使得任何class的构造函数都能放心大胆地使用其任何superclass 的instance 变量。

代码分析:

1、根据a:从heap分配内存,用来存放Bar的instance变量(index和bar)、Foo的instance变量(index),和一份「实现专属数据」。

2、根据b:instance变量被初始化为其相应缺省值,Bar的index被赋值为0,bar被赋值为null,Foo的index被赋值为0。

3、根据c:在代码65行准备创建Bar的一个对象,调用Bar的构造函数立即调用其superclass Foo的构造函数,Foo构造函数立即调用其superclass java.lang.Object的构造函数。

4、根据d:java.lang.Object构造函数返回后,在Foo对象中执行静态代码块输出Foo static,Foo静态代码块执行完,执行Bar静态代码此时代码执行到41行,准备创建Bar的第二个对象,针对这个对象,又从步骤1开始重复全部过程。

5、将要创建第二个Bar对象代码再次执行到Foo对象,由于静态对象只初始化一次,所以不会再次执行Foo的静态代码块,直接先执行初始化代码块输出Foo initialization,再执行Foo构造函数本体,根据e:Foo的index被赋值为100(这是来迷惑你的),输出Foo constructor;在Foo的构造函数中调用了printIndex函数,由于printIndex函数已经被子类Bar重写所以此时调用的是Bar中的printIndex函数,根据e:此时代码还未执行到Bar的构造函数本体,所以此时printIndex函数输出缺省值bar=null,返回Bar的index缺省值0,因此这一步输出null,0,Foo构造函数完成,返回。

6、继续构建第二个Bar对象,执行Bar的初始化代码块,输出Bar initialization,再执行构造函数,输出Bar constructor。此时Bar的index赋值100,Bar的bar对象还正在构建中所以为null,输出null,100,Bar构造函数完成。

7、Object reference bar指向heap之中最后创建完成的Bar对象,此时在第一个Bar的对象创建过程中而创建的第二Bar对象创建完成。

8、继续第一个Bar对象的创建、执行Bar的静态代码块,输出Bar static。

9、从4-8步静态代码执行完成,继续执行Foo的初始化代码块输出Foo initialization,再执行Foo的构造函数本体输出Foo constructor。在Foo的构造函数中调用了printIndex函数,由于printIndex函数已经被子类Bar重写所以此时调用的是Bar中的printIndex函数,由于在构建第二个Bar对象时已经为静态字段bar赋值,所以静态变量bar此时有值,但实例变量index还是为缺省值0,输出Bar@4633c1aa和0,Foo构造函数完成,返回。

10、执行Bar的初始化代码块输出:Bar initialization,再执行Bar的构造函数输出Bar constructor,Bar@4633c1aa和100,Bar构造函数完成。

11、Object reference bar指向heap之中最后创建完成的Bar对象,此时第一个Bar的对象创建完成。

12、66行调用bar对象函数输出Bar@4633c1aa和100.

13、67行此时给bar引用从新赋值,又从步骤一重复全部过程,由于静态只实例化一次所以输出为:Foo initialization、Foo constructor、Bar@4633c1aa、0、Bar initialization、Bar constructor、Bar@4633c1aa、100

输出结果为:

//代码在65行建构第一个Bar对象
Foo static
//代码执行到41行建构第二个Bar对象
Foo initialization
Foo constructor
null
0
Bar initialization
Bar constructor
null
100
//代码执行到56行第二个Bar对象建构完,继续建构第一个Bar对象
Bar static
Foo initialization
Foo constructor
Bar@4633c1aa
0
Bar initialization
Bar constructor
Bar@4633c1aa
100
//66行调用第一个Bar对象的函数输出结果
Bar@4633c1aa
100
//67行此时第一个Bar对象执行完,给第一个Bar引用从新建构对象
Foo initialization
Foo constructor
Bar@4633c1aa
0
Bar initialization
Bar constructor
Bar@4633c1aa
100

本文转载自:http://www.hello-code.com

芒果YOLO11改进81:主干Backbone篇之DCNv3结构:即插即用|使用pytorch代码实现,并针对YOLO11专门优化模块 阅读详情

相关推荐

在Rviz仿真环境中搭建传送带

<geometry><material>

qq_58268456的博客 936

Java 对象构造执行顺序

引用自《Java 核心技术 卷1》ch4.6 对象构造 构造器的具体处理步骤: 如果构造器第一行调用了第二个构造器, 则基于所提供的的参数执行第二个构造器 否则, 所有数据域被初始化为默认值(0、false 或null)。 按照在类声明中出现的次序, 依次执行所有域初始化语句和初始化块。 先执行静态初始化块,再执行对象初始化块。 静态初始化块只执行一次,对象初始化块在每次创建这个类的对象时均执行 执行这个构造器的主体. 代码如下:(书上的代码) public class Constru.

weixin_56915683的博客 380

手把手教你用STM32实现三相永磁同步电机FOC控制(附代码)

本文详细介绍了基于STM32的三相永磁同步电机(PMSM)FOC控制实现方法,涵盖硬件设计、软件架构、参数调试及完整代码解析。通过磁场定向控制(FOC)算法,实现高效精准的电机控制,适用于工业自动化、电动汽车等领域。文章还提供了硬件选型建议、电流采样方案对比及PID参数整定技巧,助力开发者快速掌握FOC控制技术。

weixin_29168675的博客 96

Java创建对象的初始化顺序

初始化块 初始化块通常写在类的构造方法之前,由花括号括起来,通常包含对成员属性进行初始化的语句; 初始化块分为instance初始化块和static初始化块,初始化块在构造方法执行之前被执行; static初始化块不能访问非statci成员,也不能调用非static方法,并且只在类加载时执行一次; 初始化块通常用于提取多个构造方法中的公共代码。 初始化的执行顺序 (1)在初次new一个Child类对象时,发现其有父类,则先加载Parent类,再加载Child类。 (2)加载Parent类: .

weixin_41904925的博客 245

目标检测 RT-DETR(2023)详细解读

在使用了这个技巧后,显然训练过程中,类别的标签不再是此前的0和1离散值,而是0~1的连续值。关于 Query Selection(查询向量选择),大家应该并不陌生,这个方法可谓在DETR领域大杀四方,如DAB-DETR对查询向量进行重构理解,将其解释为Anchor,DN-DETR通过查询降噪来应对匈牙利匹配的二义性所导致的训练时间长的问题,DINO提出从Encoder中选择Top-k特征进行学习等一系列方法,这都无疑向我们证明,查询向量很重要,选择好的Query能够让我们事半功倍。在RT-DETR中,

qq_51352130的博客 5869

YOLOv11改进策略【损失函数篇】| 替换激活函数为Mish、PReLU、Hardswish、LeakyReLU、ReLU6

在卷积神经网络中,激活函数通过在神经网络中引入非线性,使网络能够学习和逼近复杂函数,从而处理复杂的模式识别与分类问题。

Limiiiing的博客 2791

值按照指定顺序输出来

一个整数,大于0,不用循环和本地变量,按照n,2n,4n,8n的顺序递增,当值大于5000时,把值按照指定顺序输出来。 例:n=1237 则输出为: 1237, 2474, 4948, 9896, 9896, 4948, 2474, 1237, package 第三章; import java.util.Scanner; /* File name:homework

yangliu_w的博客 359

【QNX+Android虚拟化方案】12 - 设备虚拟化 之 Passthrough透传、Vdev Trap、HAB Socket 原理解析

【QNX+Android虚拟化方案】12 - 设备虚拟化 之 Passthrough透传、Vdev Trap、HAB Socket 原理解析

|~~~热爱生活、努力学习的小伙汁~~~| 1371

java类的初始化和对象的创建顺序

学习java编程思想--类的初始化p146 类的加载顺序* 1加载器启动找到 xxx.class文件,通过extends关键字寻找基类,先加载基类* 2类初始化先初始化static成员变量和static--->* 2先初始化父类的static成员变量和static* 3再初始化本类的static成员变量和static* 类加载之后,对象创建开始*...

weixin_33817333的博客 174

yolov5 FPGA实现及verilog代码仿真

本文介绍了一种基于FPGA的卷积神经网络加速器设计,采用混合架构实现网络功能。该系统将训练和图像预处理等复杂计算保留在PC端执行,仅将主干网络部署在FPGA上。由于片上资源限制,建议通过外接DDR存储扩展容量。文章提供了完整的Verilog HDL源码,包括卷积单元(convUnit)、卷积层(convLayerSingle)和处理单元(processingElement)等核心模块,均已通过仿真验证。该设计采用流水线结构,使用浮点运算单元实现卷积计算,支持32x32图像输入和5x5卷积核处理。系统架构图中

QQ_778132974的博客 576

如何离线环境下安装Dify插件 (可提供远程指导协助)

离线环境下安装Dify插件

litlit023的专栏 8100

JVM——深入分析对象的内存布局

本文转自:JVM——深入分析对象的内存布局 阅读目录 概述 对象头(Header) 实例数据(Instance Data) 对齐填充(Padding) 估算对象大小 参考资料 概述 一个对象本身的内在结构需要一种描述方式,这个描述信息是以字节码的方法存储在方法区中的。 Class 本身就是一个对象,都以 KB 为单位,如果 new Integer() 为了表示一个数据就占用KB级别的内存就有点不值了,下面讲解 JVM 是如何做的。 为了表示对象的属性、方法等信息,不得不需要结构描述。..

强哥叨逼叨 184

【系统分析师】2025年上半年真题:案例分析-答案及详解(回忆版)

摘要: 试题一考查面向对象分析,涉及用例模型构建的四个阶段(识别参与者、合并需求、细化描述、调整模型),分析CRM系统的参与者与用例,并说明用例间的包含、扩展和泛化关系。 试题二探讨嵌入式Docker,包括容器的轻量性、可移植性及隔离性含义,10项措施与7个规范方面的对应关系,以及优化容器切换时间的三种方法(如无状态连接优化)。 试题三聚焦数据库设计,分析订单表的函数依赖与范式分解(BCNF),讨论分解后是否保持函数依赖及无损性,并针对触发器的性能缺陷提出优化方案。 试题四解析Web开发中的MVC架构与SS

数据知道的博客 6605

深入分析Java类初始化顺序

分析Java类初始化顺序之前,先回顾下类加载的过程和时机 类加载的过程 加载:通过类名从class文件获取二进制流,生成Class对象(在方法区) 连接:包括验证、准备(类变量分配内存、赋初值)、解析(编译期确定静态类型) 初始化:初始化类 类加载的时机 主动引用 实例化对象 new 访问静态字段(final除外) get/putstatic 调用静态方法 invoke...

moni_mm的博客 340

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【Java数据结构】顺序表与数组的核心区别

摘要 顺序表与数组的核心差异在于:数组容量固定且操作原始,顺序表则通过封装数组实现动态扩容(如ArrayList默认扩容1.5倍)和便捷操作。主要区别体现在:1)容量管理:数组需手动扩容,顺序表自动处理;2)内存管理:数组需手动置null防泄漏,顺序表自动维护;3)操作接口:数组仅支持基础索引访问,顺序表封装增删查等高级操作;4)状态维护:数组不记录实际元素数,顺序表内部维护size等状态。顺序表通过封装底层数组,显著提升了开发效率和安全性。

手心朝下的博客 1219

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Java学习点滴——对象实例化

基于《Java编程思想》第四版 构造与析构 在C++中通过构造函数和析构函数来保证:对象在使用前被正确初始化,在使用后被正确回收。Java中同样存在构造函数,但是没有析构函数。之所以没有析构函数是因为对象实际的存储期由GC决定,程序员无法明确析构函数何时会被执行。 GC会在回收对象前执行Object的protected void finalize()方法,子类可以通过重写finalize()方法来...

weixin_34391854的博客 175

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

JVM - 深入分析对象的内存布局

转载: https://www.cnblogs.com/zhengbin/p/6490953.html 概述 一个对象本身的内在结构需要一种描述方式,这个描述信息是以字节码的方法存储在方法区中的。 Class 本身就是一个对象,都以 KB 为单位,如果 new Integer() 为了表示一个数据就占用KB级别的内存就有点不值了,下面讲解 JVM 是如何做的。 为了表示对象的属性、方法等信息...

qiang_zi_的专栏 174

深入分析Java内存模型

java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。可以避免像c++等直接使用物理硬件和操作系统的内存模型在不同操作系统和硬件平台下表现不同,比如有些c/c++程序可能在windows平台运行正常,而在linux平台却运行有问题。

chengxuyuan_2012的专栏 910

java判断一个数组是否包含另一个数组_java数据结构与算法之顺序表与链表深入分析(一)...

点击上方“Java专栏”,选择“置顶或者星标”第一时间阅读精彩文章!1、☞ 程序员进阶必备资源免费送「21种技术方向!」 点击查看☜2、☞《Java面试手册》.PDF 点击查看线性表抽象数据类型概述  首先来说明一下什么是抽象数据类型,我们都知道java在默认情况下,所有的基本数据类型(int,float,boolean等)都支持基本运算,如加减法,这是因为系统已帮我们实现了这些...

weixin_30164615的博客 2992

关于java的一些深入分析

在Java中,同一个类中的方法可以相互之间调用而不需要创建实例对象的主要原因是这些方法共享相同的实例上下文(对象上下文)。所以,总的来说,先加载类信息和静态变量到方法区/元空间,然后分配堆内存并初始化对象的实例变量,最后在栈内存中创建一个引用变量。,但是要知道实例方法需要用实例对象才能调用,因此把main设置为static,因为static方法在类加载时分配内存。方法内部调用实例方法时,JVM确实会隐式地创建一个实例对象,并将其传递给实例方法。引用指向当前实例,因此在同一个类的方法中,可以使用。

m0_73618763的博客 220

Java——深入分析类与对象(封装性、构造方法与匿名对象、简单Java类开发原则)

1、封装性 Java中所有面向对象的概念都是以类与对象的关系为主,下面用一个程序说明为什么要提供有封装性。 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Person person = new Person(); ...

数字世界 万物互联 573
上一篇: .NET cache对象高速缓存机制
下一篇: jQuery选择器大全
普通网友
博客等级 码龄14年 0粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值