面试官:Java对象引用都有哪些类型?
哈喽,大家好,我是世杰。
本文我为大家介绍面试官经常考察的「Java对象引用相关内容」
照例在开头留一些面试考察内容~~
面试连环call
- Java对象引用都有哪些类型?
- Java参数传递是值传递还是引用传递? 为什么?
- Java对象引用访问方式有哪些?
上一篇文章讲了 JVM 在执行 new 对象的过程中都执行了那些操作。现在我来讲一下创建对象之后的的使用
1. Java对象引用
《Java编程思想》: 每种编程语言都有自己的数据处理方式。有些时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C/C++里的指针)来操作对象。所有这些在 Java 里都得到了简化,一切都被视为对象。因此,我们可采用一种统一的语法。尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)。
Java程序需要通过栈上的引用数据来操作堆上的具体对象。对象的访问方式取决于虚拟机实现,目前主流的访问方式有使用句柄和直接指针两种。
- 直接指针:指向对象,代表对象的内存地址。
- 句柄:句柄是一种特殊的指针,可以理解为指向指针的指针,维护指向对象的指针变化,而对象的句柄本身不发生变化
1.1 直接指针
如果使用直接指针访问,那么Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而引用中存储的直接就是对象地址。
- 优势:速度更快,节省了一次指针定位的时间开销。当对象的访问非常频繁,此开销积也可节省非常可观的成本。

1.2 句柄
Java堆中划分出一块内存来作为句柄池,引用中存储对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。
- 优势:引用中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而引用本身不需要修改。
- 缺点:需要两次指针访问才能访问到对象数据。

2. 对象引用类型
在Java中一共有四种引用类型,分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。
2.1 强引用
强引用是最常见的引用类型。
- 当我们创建一个对象并将其赋值给一个引用变量时,这个引用就被称为强引用。只要强引用存在,垃圾回收器就不会回收被引用的对象。即使系统内存空间不足,JVM宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的存活对象来解决内存不足问题。
- 强引用的特性是只要有强引用存在,被引用的对象就不会被垃圾回收。
- 可以将强引用赋值为 null,这样一来,JVM 就可以适时的回收对象了(注意不是立刻回收)
public class StrongReferenceUsage {
@Test
public void stringReference(){
Object obj = new Object();
}
}
上面我们new了一个Object对象,并将其赋值给obj,这个obj就是new Object()的强引用。
2.2 软引用
软引用是用来描述一些还有用但并非必需的对象。
对于软引用关联着的对象,在系统将要发生内存溢出异常前,将会把这些对象列进回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在Java中,软引用通过java.lang.ref.SoftReference类来实现。
这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。
@Test
public void softReference(){
Object obj = new Object();
SoftReference<Object> soft = new SoftReference<>(obj);
obj = null;
log.info("{}",soft.get());
System.gc();
log.info("{}",soft.get());
}
输出结果:
22:50:43.733 [main] INFO com.flydean.SoftReferenceUsage - java.lang.Object@71bc1ae4
22:50:43.749 [main] INFO com.flydean.SoftReferenceUsage - java.lang.Object@71bc1ae4
可以看到在内存充足的情况下,SoftReference引用的对象是不会被回收的。
2.3 弱引用
弱引用也是用来描述非必需对象的,不过它的强度比软引用更弱一些。
被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收被弱引用的对象。
在Java中,弱引用通过java.lang.ref.WeakReference类来实现。
@Test
public void weakReference() throws InterruptedException {
Object obj = new Object();
WeakReference<Object> weak = new WeakReference<>(obj);
obj = null;
log.info("{}",weak.get());
System.gc();
log.info("{}",weak.get());
}
输出结果:
22:58:02.019 [main] INFO com.flydean.WeakReferenceUsage - java.lang.Object@71bc1ae4
22:58:02.047 [main] INFO com.flydean.WeakReferenceUsage - null
可以看到即便在内存充足的情况下,WeakReference引用的对象也被回收了。
2.4 虚引用
虚引用是最弱的一种引用关系。
- 一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。
- 为一个对象设置虚引用的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
- 在Java中,虚引用通过java.lang.ref.PhantomReference类来实现。
- 虚引用必须和引用队列(ReferenceQueue)联合使用
PhantomReference的作用是跟踪垃圾回收器收集对象的活动,在GC的过程中,如果发现有PhantomReference,GC则会将引用放到ReferenceQueue中,由程序员自己处理,当程序员调用ReferenceQueue.pull()方法,将引用队列中的对象引用移除之后,Reference对象会变成Inactive状态,意味着被引用的对象可以被回收了。
@Slf4j
public class PhantomReferenceUsage {
@Test
public void usePhantomReference(){
ReferenceQueue<Object> rq = new ReferenceQueue<>();
Object obj = new Object();
PhantomReference<Object> phantomReference = new PhantomReference<>(obj,rq);
obj = null;
log.info("{}",phantomReference.get());
System.gc();
Reference<Object> r = (Reference<Object>)rq.poll();
log.info("{}",r);
}
}
输出结果:
07:06:46.336 [main] INFO com.flydean.PhantomReferenceUsage - null
07:06:46.353 [main] INFO com.flydean.PhantomReferenceUsage - java.lang.ref.PhantomReference@136432db
我们看到get的值是null,而GC过后,poll是有值的。
因为PhantomReference引用的是需要被垃圾回收的对象,所以在类的定义中,get一直都是返回null:
public T get() {
return null;
}
『总结』
- 强引用是最常见的类型,但如果内存空间不足,可能会导致OutOfMemoryError错误。
- 软引用的对象在系统内存即将溢出时会被回收,适用于缓存等情况。
- 弱引用的对象无论当前内存空间足够与否都会被回收,适用于实现对象的单例模式等。
- 虚引用的主要目的是为了能收到系统通知,以便在对象被回收时进行相应的处理。
在程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速 JVM 对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OOM)等问题的产生。
3. 值传递 vs 引用传递
3.1 定义
- 值传递:方法参数传入的是参数的备份,对参数的修改并不会影响本身
- 引用传递:方法参数传入的都是参数的引用,对参数的修改会影响本身
Java的参数传递是值传递还是引用传递?
先说结论:Java本质上都是值传递
3.2 Java对象类型
说到值传递和引用传递我们不得不提到两个概念:值类型和引用类型。
基本类型是值类型。JVM赋值时,直接在栈上生成值

类、接口、数组、对象、基本类型的包装类都是引用类型。JVM赋值时,在栈上生成引用,在堆中生成数据

3.3 为什么?
先看一段代码
@Test
public void testReference() {
Base base = new Base();
base.setName("main");
set2(base);
System.out.println(base.getName());
}
private void set1(Base base) {
base.setName("set1");
}
private void set2(Base base) {
base = new Base();
base.setName("set2");
}
上述的方法,调用set1的执行结果是【set1】,调用set2的执行结果是【main】
由此可以看出,方法入参传入的都是副本
- 当是基本类型时,传入的是基本类型的拷贝副本,修改基本类型的【入参】并不会影响【实参】
- 当是引用类型时,传入的引用类型依旧是拷贝副本,但是此时的副本是拷贝地址,因此修改入参会影响到实现的值,因此入参和实参的指向都是堆中同一个内存区域,例如set1方法。但当为入参重新赋值一个新的地址,并在修改此地址指向的内存区域,就不会影响实参中的值,例如set2方法。
所以Java是值传递
参考文章
面试官:Java对象引用都有哪些类型?的更多相关文章
- 硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行
1. 什么是MVCC MVCC全称是Multi-Version Concurrency Control(多版本并发控制),是一种并发控制的方法,通过维护一个数据的多个版本,减少读写操作的冲突. 如果没 ...
- 面试官:Java中对象都存放在堆中吗?你知道逃逸分析?
面试官:Java虚拟机的内存分为哪几个区域? 我(微笑着):程序计数器.虚拟机栈.本地方法栈.堆.方法区 面试官:对象一般存放在哪个区域? 我:堆. 面试官:对象都存放在堆中吗? 我:是的. 面试官: ...
- 你都这么拼了,面试官TM怎么还是无动于衷
面试,对于每个人而然并不陌生,可以说是必须经历的一个过程了,小到一场考试,大到企业面试,甚至大型选秀...... 有时自己明明很努力了,但偏偏会在面试环节出了插曲,比如,紧张就是最容易出现的了. 我相 ...
- 你都这么拼了,面试官TM怎么还是无动于衷?
前言 面试,对于每个人而然并不陌生,可以说是必须经历的一个过程了,小到一场考试,大到企业面试,甚至大型选秀...... 有时自己明明很努力了,但偏偏会在面试环节出了插曲,比如,紧张就是最容易出现的了. ...
- 一个static和面试官扯了一个小时,舌战加强版
一:背景 1. 讲故事 最近也是奇怪,在社区里看到好几篇文章聊static 的玩法以及怎么拿这个和面试官扯半个小时,有点意思,点进去看都是java版的,这就没意思了,怎么也得有一篇和面试官扯C# 中的 ...
- 美团面试官问我: ZGC 的 Z 是什么意思
本文的阅读有一定的门槛,请先了解 GC 的基本只知识. 现代垃圾收集器的演进大部分都是往减少停顿方向发展. 像 CMS 就是分离出一些阶段使得应用线程可以和垃圾回收线程并发,当然还有利用回收线程的并行 ...
- 面试官最爱的volatile关键字
在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性 ...
- 互联网公司的面试官是如何360°无死角考察候选人的?[z]
[z]https://juejin.im/post/5c0e47ebf265da614e2be9a7 一.写在前面 最近收到不少读者反馈,说自己在应聘一些中大型互联网公司的Java工程师岗位时遇到了不 ...
- 面试官:讲讲redis的过期策略如何实现?
时隔多日,小菜鸡终于接到阿里的面试通知,屁颠屁颠的从上海赶到了杭州. 经过半个小时的厮杀: 自我介绍 hashMap和ConcurrentHashMap区别 jdk中锁的实现原理 volatile的使 ...
- 阿里二面,面试官居然把 TCP 三次握手问的这么细致
TCP 的三次握手和四次挥手,可以说是老生常谈的经典问题了,通常也作为各大公司常见的面试考题,具有一定的水平区分度.看似是简单的面试问题,如果你的回答不符合面试官期待的水准,有可能就直接凉凉了. 本文 ...
随机推荐
- 如何将 iPad 用作 Windows 计算机的第二台显示器?
安装第二台显示器是扩大屏幕空间的一种常用方法.如果您偶尔只需要第二个显示器(例如您偶尔在家中工作),但又不想购买整个第二个显示器,则可以将 iPad 用作廉价的替代品. 要将 iPad 用作Windo ...
- 记一次ThreadLocal中的用户信息混乱问题
前言 记录一次开发中遇到的关于 ThreadLocal 问题,场景是数据库表中的操作人总是无缘无故的被更改,排查了几遍代码才发现是 ThreadLocal 没有及时清理导致的. 一.为什么使用 Thr ...
- 使用jsbarcode生成条形码
安装 yarn add jsbarcode 使用 // HTMLElement 承载条形码的元素 svg/canvas // text 显示在条形码下方的文字 // option 条形码的配置项 具体 ...
- 干货 springcloud之 poenFeign的使用
PoenFeign集成到springcloud项目中 先创建一个springboot项目 这里就不多说了 application.yml文件: server: port: 8082spring: ap ...
- itest(爱测试) 紧急 BUG 修复版(4.5.6)发布,,开源BUG 跟踪管理 & 敏捷测试管理&极简项目管理软件
itest 简介 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理4合1,又有丰富的统计分析.可按测试包分配测试用例执行,也可建测试迭代(含任务, ...
- Stable diffusion采样器详解
在我们使用SD web UI的过程中,有很多采样器可以选择,那么什么是采样器?它们是如何工作的?它们之间有什么区别?你应该使用哪一个?这篇文章将会给你想要的答案. 什么是采样? Stable Diff ...
- Matlab打印运行进度
在运行matlab程序的过程中,有时候需要实时地掌握程序运行的进度,尤其对于一些耗时较长的循环操作,能够及时地输出运行进度,显得非常有必要. 打印进度条的实现方式就是不断地退格.输出. 退 ...
- mysql中,时间类型datetime和timestamp的区别
TIMESTAMP和DATETIME的相同点: 两者都可用来表示 YYYY-MM-DD HH:MM:SS 类型的日期. TIMESTAMP和DATETIME的不同点: 1> 两者的存储方式不一 ...
- Go变量作用域精讲及代码实战
关注作者,复旦AI博士,分享AI领域与云服务领域全维度开发技术.拥有10+年互联网服务架构.AI产品研发经验.团队管理经验,同济本复旦硕博,复旦机器人智能实验室成员,国家级大学生赛事评审专家,发表多篇 ...
- CTF反序列化wp(ciscn,nss,ctfshowweb入门)
[CISCN 2023 华北]ez_date 题目: <?php error_reporting(0); highlight_file(__FILE__); class date{ public ...