面试官:Java对象引用都有哪些类型?

news/2024/11/17 19:28:21/文章来源:https://www.cnblogs.com/xieshijie/p/18293913

哈喽,大家好🎉,我是世杰

本文我为大家介绍面试官经常考察的「Java对象引用相关内容」

照例在开头留一些面试考察内容~~

面试连环call

  1. Java对象引用都有哪些类型?
  2. Java参数传递是值传递还是引用传递? 为什么?
  3. Java对象引用访问方式有哪些?

上一篇文章讲了 JVM 在执行 new 对象的过程中都执行了那些操作。现在我来讲一下创建对象之后的的使用

1. Java对象引用

《Java编程思想》: 每种编程语言都有自己的数据处理方式。有些时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C/C++里的指针)来操作对象。所有这些在 Java 里都得到了简化,一切都被视为对象。因此,我们可采用一种统一的语法。尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)

Java程序需要通过栈上的引用数据来操作堆上的具体对象。对象的访问方式取决于虚拟机实现,目前主流的访问方式有使用句柄和直接指针两种。

  • 直接指针:指向对象,代表对象的内存地址。
  • 句柄:句柄是一种特殊的指针,可以理解为指向指针的指针,维护指向对象的指针变化,而对象的句柄本身不发生变化

1.1 直接指针

如果使用直接指针访问,那么Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而引用中存储的直接就是对象地址

  • 优势:速度更快,节省了一次指针定位的时间开销。当对象的访问非常频繁,此开销积也可节省非常可观的成本。

img

1.2 句柄

Java堆中划分出一块内存来作为句柄池,引用中存储对象的句柄地址,而句柄中包含了对象实例数据类型数据各自的具体地址信息。

  • 优势:引用中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而引用本身不需要修改
  • 缺点:需要两次指针访问才能访问到对象数据。

img


2. 对象引用类型

在Java中一共有四种引用类型,分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。

2.1 强引用

强引用是最常见的引用类型。

  • 当我们创建一个对象并将其赋值给一个引用变量时,这个引用就被称为强引用。只要强引用存在,垃圾回收器就不会回收被引用的对象。即使系统内存空间不足,JVM宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的存活对象来解决内存不足问题。
  • 强引用的特性是只要有强引用存在,被引用的对象就不会被垃圾回收。
  • 可以将强引用赋值为 null,这样一来,JVM 就可以适时的回收对象了(注意不是立刻回收)
public class StrongReferenceUsage {@Testpublic void stringReference(){Object obj = new Object();}
}

上面我们new了一个Object对象,并将其赋值给obj,这个obj就是new Object()的强引用。

2.2 软引用

软引用是用来描述一些还有用但并非必需的对象。

  • 对于软引用关联着的对象,在系统将要发生内存溢出异常前,将会把这些对象列进回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在Java中,软引用通过java.lang.ref.SoftReference类来实现。

  • 这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。

    @Testpublic 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类来实现。

    @Testpublic 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 {@Testpublic 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 定义

  1. 值传递:方法参数传入的是参数的备份,对参数的修改并不会影响本身
  2. 引用传递:方法参数传入的都是参数的引用,对参数的修改会影响本身

Java的参数传递是值传递还是引用传递?

先说结论:Java本质上都是值传递

3.2 Java对象类型

说到值传递和引用传递我们不得不提到两个概念:值类型和引用类型

基本类型是值类型。JVM赋值时,直接在栈上生成值

java_value_type

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

java_reference_type

3.3 为什么?

先看一段代码

    @Testpublic 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】

由此可以看出,方法入参传入的都是副本

  1. 当是基本类型时,传入的是基本类型的拷贝副本,修改基本类型的【入参】并不会影响【实参】
  2. 当是引用类型时,传入的引用类型依旧是拷贝副本,但是此时的副本是拷贝地址,因此修改入参会影响到实现的值,因此入参和实参的指向都是堆中同一个内存区域,例如set1方法。但当为入参重新赋值一个新的地址,并在修改此地址指向的内存区域,就不会影响实参中的值,例如set2方法。

所以Java是值传递


参考文章

  1. https://mp.weixin.qq.com/s/r5cMTmQjNwYwiX7pLx_52Q

  2. JAVA对象的创建及内存分配详解

  3. 对象和引用

  4. 理解java对象的引用

  5. 一文读懂java中的Reference和引用类型

  6. 这一次,彻底解决Java的值传递和引用传递

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/741699.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习策略篇:详解如何使用来自不同分布的数据,进行训练和测试(Training and testing on different distributions)

如何使用来自不同分布的数据,进行训练和测试 深度学习算法对训练数据的胃口很大,当收集到足够多带标签的数据构成训练集时,算法效果最好,这导致很多团队用尽一切办法收集数据,然后把它们堆到训练集里,让训练的数据量更大,即使有些数据,甚至是大部分数据都来自和开发集、…

Matebook14 2020款 更换固态(全流程)

Matebook14 2020款 更换固态全流程 因为工作的原因需要升级存储,我的老款的Matebook14只有512G。网络上的中文教程普遍比较古老。特此写下这篇笔记希望能帮助到有需要的朋友。 工具螺丝刀(四花00和六花T4) 新的固态硬盘 U盘(容量不小于1G) 移动硬盘(容量不能小于你的系统…

Linux安装JDK详细教程

Linux安装JDK详细教程(图文教程) 这里介绍两种方式:yum安装方式和手动安装1、yum安装 1.1 查看JDK版本,找到你想要安装的JDK版本,这里以 JDK1.8 为例 输入命令:yum -y list java*1.2 安装JDK1.8 输入命令:yum install -y java-1.8.0-openjdk.x86_64 没权限执行这行:sud…

mongodb数据库恢复

一、从备份中恢复 使用mongodump和mongorestore mongodump:MongoDB官方提供的备份工具,可以将MongoDB数据库中的数据导出为BSON格式的文件。通过该工具,可以备份整个数据库、指定的集合或查询的数据。 mongorestore:MongoDB官方提供的恢复工具,用于将mongodump导出的BSON文…

Java虚拟机(JVM)修复

一、确定问题原因 首先,需要明确Java虚拟机出现问题的具体原因。这可以通过以下方式进行: 查看错误日志:JVM和Java应用程序会生成日志文件,这些文件记录了运行时的详细信息,包括错误信息和系统警告。通过查看这些日志,可以获得导致JVM故障的线索。 使用调试工具:如jstac…

SQLite数据库恢复

一、使用备份文件恢复 直接替换法: 如果之前有备份数据库文件,最简单直接的恢复方法就是将备份文件直接替换掉损坏的或丢失的数据库文件。 这种方法简单快捷,但需要注意在替换过程中确保没有其他程序正在访问数据库文件,以免造成数据不一致。 使用SQLite命令行工具恢复: S…

sqlite数据库解密恢复

关于SQLite数据库解密恢复的问题,需要明确的是,SQLite本身并不直接支持加密功能。SQLite数据库文件(通常是.db或.sqlite文件)在默认情况下是不加密的,即数据以明文形式存储。因此,当提到“解密恢复”时,可能指的是对通过第三方工具或方法加密过的SQLite数据库进行解密和…

浪潮服务器维修数据恢复

一、初步评估与故障诊断 收集信息: 了解服务器的型号、配置、操作系统、RAID配置(如RAID5等)以及数据丢失的具体情况。 查看服务器的日志、系统状态指示灯、硬件自检报告等信息,初步判断数据丢失的原因。 确定恢复策略: 根据故障诊断结果,制定合适的恢复策略。可能包括数…

IBM服务器维修数据恢复

一、评估损失和风险 评估数据损失程度:首先,需要确定数据丢失的严重程度和范围,以便制定合适的恢复策略。 评估潜在风险:了解数据丢失的原因(如硬件故障、软件问题、人为失误等),以及恢复过程中可能遇到的风险和挑战。 二、创建数据备份 在进行任何维修或恢复操作之前,…

Windows下升级JDK

1. 官网下载安装包,官网地址:https://www.oracle.com/cn/java/technologies/downloads/#jdk21-windows 2. java -version检查现有jdk版本3. 修改环境变量 4. java -version检查jdk版本,未生效 输出环境变量,发现确实配置已经成功 以上仅供参考,如有疑问,留言联系

案例分享:Qt modbusTcp调试工具(读写Byte、Int、DInt、Real、DReal)(当前v1.0.0)

前言西门子PLC、台达PLC、法兰克机床等等多年以前玩得比较多,有tcp/ip通讯也有modbus通讯,modbus又分为网络,485,232等。  医疗项目,焊接机器人项目,工控机床项目,数控项目,物联网项目用的挺多的,将关键的通信技术抽离出来,单独弄成工具。  最近调绞车,遇到了mo…