比喻帮你深入理解 JAVA 对象

本文详细介绍Java对象在HotSpot JVM中的创建位置、创建步骤、对象结构及访问方式。对象主要在堆区分配,经历类加载检查、内存分配、零值初始化、对象头设置及构造方法调用等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:本文中的JVM限于HotSpot JVM,详细介绍了,对象在哪里创建、创建的步骤是什么、创建之后的对象长什么样、以及想要使用该对象的时候如何访问。

1 对象在哪里创建

这个问题,就是在你买房子之前,要确定在哪里买。排除房产投资什么的,肯定是在你的工作地买啦。

Java 是面向对象的编程语言,那么,对象到底是在哪里创建的呢?

首先明确一点,几乎所有的对象实例和数组都在堆中分配。这里需要了解 JVM 内存的划分,详见个人另一篇博客JVM 内存划分、GC 机制与性能优化

这里写图片描述

看上面的图,对象优先在Eden中分配,Eden空间不够的时候,会触发一次Minor GC。当需要创建大对象(需要大量连续内存空间的java对象)的时候,则会放入老年代中。如果Major GC之后还是老年代不足,就会直接抛出异常。

2 对象如何创建

这个过程可以概括为:
检查是否进行过类加载——分配内存给新生对象——分配的空间初始化为零值(不包括对象头)——设置对象头——init

听起来太抽象?好吧,换一种表述方式:
检查房地产公司是否合法——确定要买100平米户型——清空房间内原本装修遗留的建材——房子和户主信息匹配登记——房产证下来

下面分别详细阐述:

2.1 检查是否进行过类加载

需要创建一个对象的时候,JVM首先会去检查这个指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用的类是否已经被加载、解析过。如果没有,必须先执行相应的类加载过程。类似于买房子的时候,先要检查这个房地产公司是不是在工商局注册的合法公司,有没有土地买卖权,购买者的户口在当地符不符合限购令的规定啊等等。

2.2 分配内存给新生对象

类加载检查通过后,为新生对象分配内存。对象需要的内存大小在类加载完成后就可以完全确定。分配内存的过程,类似于你要从这个开发商的楼盘中买个100平米的房子,出了100平米的钱,就得给你100平米房间的钥匙。分配的算法有两种:

内存分配算法适用于算法描述
指针碰撞Serial、ParNew收集器堆中内存绝对规整,一边是用过的,一边是未使用的,二者之间的分界点放一个指针。需要分配内存给一个对象的时候,就把指针向空闲方向移动一段与对象大小相等的距离
空闲列表CMS收集器空闲区域与使用过的区域交错排列,JVM维护一个列表,里面记录着哪块是可用的。分配的时候从表中找出合适大小的空间即可

接下来,每天那么多人去看房子,可能出现你刚准备交首付,另一个人也看上了同一个房子要付款,也就是所谓的创建对象时的并发安全问题。这个问题有两种解决方案:

  • CAS加失败重试
  • 每个线程在堆中预先分配一小块内存(TLAB,本地线程分配缓冲)。哪个线程需要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完要分配新的TLAB时,才同步锁定。

2.3 分配的空间初始化为零值(不包括对象头)

内存分配完成后,虚拟机将该内存空间初始化为零值(不包括对象头)。为什么要进行这样的操作?对象的实例字段在java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型对应的零值。

这个过程类似于,开发商开发楼盘的时候,首先要把每个房间的墙、门砸好,窗户安好,下水道通了等等。房间里就会遗留下来各种木头、梯子、油漆桶等等,这时候就要先把这些遗留材料清空掉,能保证你从旧房子里搬家具过来就可以直接住。但是对象头绝对不能清空,对象头清空了就没人知道这个房子是不是你的了。

2.4 设置对象头

JVM设置对象的对象头,包括该对象是哪个类的实例,哈希码,GC年龄分代等信息。对象头后面会详细讲。这个过程类似于房子和户主信息匹配登记。

2.5 init

上面的工作之后,对JVM来说,新的对象已经创建好了。但是对于程序员来说,这一切才刚刚开始。执行new指令后,接着执行init
方法,对程序员来说,这个对象才真正可用。

这个过程类似于,开发商给你钥匙,你可以住进去了。但是这个房子真正属于你(拥有买卖权),得等到房产证下来。

3 对象到底长什么样

这里我们需要了解的是你所购买的房屋的结构,几室几厅,厕所在哪里等等。

对象分为三部分:对象头、实例数据、对齐填充

item详述
对象头分为两部分,一是用于存储对象自身的运行时数据,包括哈希码、GC年龄分代、锁标志状态、线程持有的锁、偏向线程ID、偏向时间戳等等,官方称为“Mark Word”。另一部分是类型指针,JVM通过该指针确定该对象是哪个对象的实例
实例数据对象的具体内容
对齐填充并非必然存在,只是因为JVM中对象大小必须是八字节的整数倍,该部分用来补全

注意,普通java对象的元数据信息可以确定该对象的大小,但是数组不可以。因此数组的对象头还应有一块存储数组长度的数据。

4 对象如何被访问

当你创建一个对象之后,为了使用,总得先访问该对象。

首先需要复习一个知识点。Java虚拟机栈中,存储局部变量表、操作数栈、动态链接、方法返回地址和一些额外的附加信息。其中局部变量表存放了三个信息:

  • 各种基本数据类型(boolean、byte、char、short、int、float、long、double)
  • 对象引用(reference)
  • returnAddress地址(指示JVM的指令执行到哪一行)

也就是说,访问的起始点,永远是局部变量表中的对象引用(reference)。

4.1 通过句柄访问

这里写图片描述

对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要被修改

4.2 通过直接指针访问

这里写图片描述

速度更快,节省了一次指针定位的时间开销,HotSpot采取的就是这种方式。

如有转载,请务必标明出处
http://blog.youkuaiyun.com/antony9118/article/details/53055368

<think>嗯,用户让我用通俗易懂的语言介绍一下Java接口。首先,我得想想用户可能是什么背景。可能是刚开始学Java的新手,或者对面向对象编程概念不太熟悉的人。用户需要的是简单明了的解释,避免用太多专业术语,但又得准确。 首先,接口的定义。接口在Java里是一个抽象类型,用来定义方法集合,但不实现它们。这点和类不同,类可以实例化,而接口不行。但如何用日常例子来解释呢?比如合同或者协议,可能更形象。 然后,接口的作用。为什么需要接口?主要是实现多继承,因为Java不支持多继承,但接口可以多重实现。另外,实现解耦,提高代码的灵活性和可维护性。这里可能需要举个实际例子,比如不同设备通过统一接口连接,比如USB接口的例子,这样用户容易理解。 接下来,接口的特性。比如接口中的方法默认是public abstract的,变量是public static final的。还有Java 8之后的默认方法和静态方法,这些可能需要提到,但不用太深入,避免让用户感到复杂。 还要比较接口和抽象类的区别。用户可能混淆这两者。比如抽象类可以有构造方法,而接口不能;接口支持多继承,而抽象类不行。这些关键点需要简单说明。 然后,举一个实际的代码例子。比如定义一个Animal接口,有eat()和sleep()方法,然后让Cat和Dog类实现这个接口,展示如何具体实现方法。这样用户可以看到代码结构,更容易理解。 还要注意用户可能的问题,比如什么时候用接口,什么时候用抽象类。虽然用户没直接问,但可能在解释中稍微提到,助他们更好地区分。 最后,总结接口的好处,比如标准化、解耦、扩展性等,用简单的话说明,让用户记住核心优点。 需要检查有没有用专业术语,尽量替换成日常用语。比如“解耦”可以说成“让不同部分独立变化不影响其他部分”之类的。确保例子贴切,比如USB或者电源插头,都是常见的比喻助用户形成直观印象。 可能还要考虑用户是否有其他编程经验,比如如果了解其他语言的接口,可以对比说明,但用户没提,所以暂时不用。重点放在Java接口本身,保持解释的专注性。 最后,组织回答的结构,先定义,再作用,特性,例子,注意事项,总结。这样逐步推进,结构清晰,符合用户要求的“结构清晰,逐步解决问题”。</think>我来用"USB接口"的比喻你理解Java接口: 1. 什么是接口? 就像电脑上的USB插槽定义了统一的形状和充电/传数据功能,Java接口是提前制定好的"功能清单"。例如: ```java // 定义USB接口的规范 public interface USB { void charge(); // 充电功能 void transferData(); // 传输数据功能 } ``` 2. 接口的实际应用 当设备(类)实现接口时,就相当于承诺要完成接口规定的所有功能: ```java // 手机实现USB接口 class Phone implements USB { public void charge() { System.out.println("5V 2A充电"); } public void transferData() { System.out.println("通过USB线传输照片"); } } // 充电宝实现USB接口 class PowerBank implements USB { public void charge() { System.out.println("输出5V 1A电流"); } public void transferData() { System.out.println("本设备不支持数据传输"); } } ``` 3. 接口的核心价值 - 统一标准:所有USB设备都遵循同样的充电规范 - 灵活替换:电脑不用关心插的是手机还是充电宝,只要符合USB规范就能工作 - 强制约定:实现接口的类必须完成所有功能(就像没有充电功能的U盘就是不合格产品) 4. 实际开发中的典型应用 - 定义日志记录规范(不同类可以用文件记录/数据库记录等不同方式实现) - 支付接口(支付宝/微信支付/银联都遵循同样的支付流程) - 数据访问接口(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值