JAVA的引用与C++的指针有什么区别

news2024/11/28 21:58:49

JAVA的引用与C++的指针有什么区别

  • 1. Java值类型与引用类型
    • 1.1 变量初始化
    • 1.2 变量赋值
    • 1.3 函数传参
  • 2. Java数据存储方式
    • 2.1 Java局部变量&&Java方法参数
    • 2.2 Java数组类型引用和对象
    • 2.3 String类型数据
  • 3. Java引用类型
    • 3.1 强引用
    • 3.2 软引用
    • 3.3 弱引用
    • 3.4 虚引用
  • 4. JAVA的引用与C++的指针有什么区别

在这里插入图片描述
在这里插入图片描述

1. Java值类型与引用类型

1.1 变量初始化

int num=10;
String str="hello"

1.2 变量赋值

从上图可以显而易见,num是int基本类型变量,值就直接保存在变量中。str是String引用类型变量,变量中保存的只是实际对象对应的地址信息,而不是实际对象数据。对于而这特性,如下:

num=20;
str ="java";

对于基本类型变量num,赋值运算符将会直接修改变量的值,原来的数据将被覆盖掉,被替换为新的值。对于引用类型变量str,赋值运算符只会改变变量中所保存的对象的地址信息,原来对象的地址被覆盖掉,重新写入新对象的地址数据。但原来的对象本身并不会被改变,只是不再被任何引用所指向的对象,即“垃圾对象”,后续会被垃圾回收器回收。

1.3 函数传参

// 基本类型参数,原始value不会被更改
public void func(int value) {
    value = 100;
}

// 对于没有提供修改自身的成员方法引用类型,原始str不会被更改
public void func(String str) {
    str = "hello";
}

StringBuilder sb = new StringBuilder("test");

// 对于提供修改自身的成员方法引用类型,原始的sBuilder会被更改
public void func(StringBuilder sBuilder) {
    sBuilder.append("aa");
}

// 原始的sBuilder不会被更改
public void test(StringBuilder sBuilder) {
    sBuilder = new StringBuilder("111");
}

说明:对于第三种情况:

对于第四种情况:

2. Java数据存储方式

2.1 Java局部变量&&Java方法参数

对于局部变量和方法传递的参数在jvm中的存储方式是相同的,都是存储在栈上开辟的空间中。方法参数空间在进入方法时开辟,方法退出时进行回收。以32为JVM为例,boolean、byte、short、char、int、float以及对应的引用类型都是分配4字节大小的空间,long、double分配8字节大小空间。对于每一个方法来说,最多占用空间大小是固定的,在编译时就已经确定了。

当在方法中声明一个int变量i=0Object变量obj=null时,此时仅仅在栈上分配空间,不影响到堆空间。当new Object()时,将会在堆中开辟一段内存空间并初始化Object对象。

2.2 Java数组类型引用和对象

当声明数组时,int[] arr=new int[2];数组也是对象,arr实际上是引用,栈上占用4个字节大小的存储空间,而是会在堆中开辟相应大小空间进行存储,然后arr变量指向它。当声明一个二维数组时,如:int[][] arr2=new int[2][4],arr2同样在栈中占用4个字节,在堆内存中开辟长度为2,类型为int[]的数组对象,然后arr2指向这个数组。这个数组内部有两个引用类型(大小为4个字节),分别指向两个长度为4类型为int的数组。内存分布如图:

所以当传递一个数组给一个方法时,数组的元素在方法内部是可以被修改的,但是无法让数组引用指向新的数组。其实,还可以声明:int [][] arr3=new int[3][],内存分布如下:

2.3 String类型数据

对于String类型,其对象内部需要维护三个成员变量,char[] chars,int startIndex, int length。chars是存储字符串数据的真正位置,在某些情况下是可以共用的,实际上String类型是不可变类型。例如:String str=new String("hello"),内存分布如下:

3. Java引用类型

在JAVA中提供了四种引用类型:强引用、软引用、弱引用和虚引用。在四种引用类型中,只有强引用FinalReference类型变量是包内可见的,其他三种引用类型均为public,可以在程序中直接使用。

3.1 强引用

强引用是使用最普遍的引用。如果一个对象具有强引用,那么垃圾回收器绝不会回收它。

之前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。比如下面这段代码中的object和str都是强引用:

Object object = new Object();
String str = "StrongReference";

如果一个对象具有强引用,那就类似于必不可少的物品,不会被垃圾回收器回收。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不回收这种对象。

public class StrongReference {
	public static void main(String[] args) {
		new StrongReference().method1();
	}
	public void method1(){
		Object object=new Object();
		Object[] objArr=new Object[Integer.MAX_VALUE];
	}
}

运行结果:

当运行至Object[] objArr = new Object[Integer.MAX_VALUE]时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当method1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。

如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

比如ArraryList类的clear方法中就是通过将引用赋值为null来实现清理工作的

在这里插入图片描述

public void clear() {
      modCount++;
 
      // Let gc do its work
      for (int i = 0; i < size; i++)
          elementData[i] = null;
 
      size = 0;
}

在ArrayList类中定义了一个私有的变量elementData数组,在调用方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型特别适用,这样就可以及时释放内存。

强引用特点:

  • 强引用可以直接访问目标对象
  • 只要有引用变量存在,垃圾回收器永远不会回收。JVM即使抛出OOM异常,也不会回收强引用所指向的对象。
  • 强引用可能导致内存泄漏问

3.2 软引用

软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。

import java.lang.ref.SoftReference;
 
public class SoftRef {  
 
    public static void main(String[] args){  
        System.out.println("start");            
        Obj obj = new Obj();            
        SoftReference<Obj> sr = new SoftReference<Obj>(obj);  
        obj = null;  
        System.out.println(sr.get());  
        System.out.println("end");     
    }       
}  
 
class Obj{  
    int[] obj ;  
    public Obj(){  
        obj = new int[1000];  
    }  
}

在这里插入图片描述
当内存足够大时可以把数组存入软引用,取数据时就可从内存里取数据,提高运行效率

软引用在实际中有重要的应用,例如浏览器的后退按钮,这个后退时显示的网页内容可以重新进行请求或者从缓存中取出:

(1)如果一个网页在浏览结束时就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建

(2)如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出这时候就可以使用软引用

3.3 弱引用

弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。所以被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。

import java.lang.ref.WeakReference;
 
public class WeakRef {
    public static void main(String[] args) {
        WeakReference<String> sr = new WeakReference<String>(new String("hello"));
        System.out.println(sr.get());
        System.gc();                //通知JVM的gc进行垃圾回收
        System.out.println(sr.get());
    }
}

运行结果:
在这里插入图片描述
在使用软引用和弱引用的时候,我们可以显示地通过System.gc()来通知JVM进行垃圾回收,但是要注意的是,虽然发出了通知,JVM不一定会立刻执行,也就是说这句是无法确保此时JVM一定会进行垃圾回收的。

弱引用还可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

3.4 虚引用

虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收的活动。

虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
 
 
public class PhantomRef {
    public static void main(String[] args) {
        ReferenceQueue<String> queue = new ReferenceQueue<String>();
        PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
        System.out.println(pr.get());
    }
}

使用-Xmx2M限定堆内存,使用WeakHashMap的代码正常运行结束,而使用HashMap的代码段抛出异常:java.lang.OutOfMemoryError: Java heap space。由此可见,WeakHashMap会在系统内存紧张时使用弱引用,自动释放掉持有弱引用的内存数据。但如果WeakHashMap的key都在系统内持有强引用,那么WeakHashMap就退化为普通的HashMap,因为所有的数据项都无法被自动清理。

引用类型被回收时间用途生存时间
强引用从来不会对象的一般状态JVM停止运行时
软引用内存不足时对象缓存内存不足时
弱引用jvm垃圾回收时对象缓存gc运行后
虚引用未知未知未知
  • 在实际程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生

  • 利用软引用和弱引用解决OOM问题:假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。

  • 设计思路是:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。

4. JAVA的引用与C++的指针有什么区别

Java 的引用和 C++ 的指针在概念上有一些相似之处,但也存在一些重要的区别。以下是它们之间的主要区别:

  1. 内存管理:

    • Java 引用: Java 使用自动内存管理(垃圾回收)。在 Java 中,对象的内存管理由垃圾收集器负责,程序员无需手动释放内存。引用的生命周期由垃圾收集器来监控,当没有任何引用指向一个对象时,该对象将被认为是不可达的,垃圾收集器会回收其内存。
    • C++ 指针: C++ 使用手动内存管理。程序员负责为分配的内存进行释放。通过 new 运算符分配的内存必须由程序员使用 delete 运算符手动释放,否则可能导致内存泄漏。
  2. 空引用(Null References):

    • Java 引用: 在 Java 中,引用可以是空(null),表示不指向任何对象。对空引用进行解引用会导致 NullPointerException
    • C++ 指针: C++ 中的指针可以为 nullptr(在 C++11 之前通常使用 NULL),表示不指向任何地址。对空指针进行解引用会导致未定义行为。
  3. 类型安全:

    • Java 引用: 引用是类型安全的,编译器会在编译时执行类型检查,确保引用只能指向与其声明类型相符的对象。
    • C++ 指针: 指针可以进行类型转换,并且在编译时不进行类型检查。这可能导致类型不匹配的错误,需要程序员自己负责确保类型安全性。
  4. 指针算术:

    • Java 引用: Java 不支持指针算术,不允许直接对引用进行指针运算。
    • C++ 指针: C++ 允许指针进行算术运算,可以通过指针进行地址运算。
  5. 多级引用(Reference Levels):

    • Java 引用: Java 中只有一级引用,垃圾收集器负责处理对象之间的引用关系。
    • C++ 指针: C++ 允许多级指针,即指针的指针。这种情况在一些特定的应用场景中可能会更灵活,但也需要谨慎处理。

总体而言,Java 的引用更加高级和抽象,提供了更简单的内存管理和类型安全性,而 C++ 的指针更灵活但也更容易引入一些潜在的错误。选择使用引用还是指针取决于编程语言的设计哲学以及特定的应用需求。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot启动时执行初始化操作还只会用@PostConstruct?进来看看其它方式~

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

网易云商冯旻伟:“大模型是下一代信息系统的大脑”

编者按 AIGC时代&#xff0c;大模型在智能客服领域的应用一直备受关注&#xff0c;其不断演进的技术给用户体验和业务效率带来了全新的可能性。 近日&#xff0c;我们有幸采访了网易云商AI技术线的负责人冯旻伟&#xff0c;深入了解了他们在智能客服方面的创新和实践。从文字交…

grep笔记240103

常用选项&#xff1a;&#xff1a; -i&#xff1a;忽略大小写进行匹配。 -v&#xff1a;反向匹配&#xff0c;只打印不匹配的行。 -n&#xff1a;显示匹配行的行号。 -r&#xff1a;递归查找子目录中的文件。 -l&#xff1a;只打印匹配的文件名。 -c&#xff1a;只打印匹配的行…

打造专属个人或企业知识付费平台,核心功能设计

在当今数字化时代&#xff0c;知识付费市场正在迅速崛起&#xff0c;而私域流量的概念也日益受到重视。私域流量指的是企业通过自有渠道获取的、能够自由支配的流量&#xff0c;这种流量具有更高的用户粘性和转化率。因此&#xff0c;打造一个基于私域流量的知识付费小程序平台…

【响应式编程-03】常见的函数式接口

一、简要描述 使用Lambda的前提 必须有一个函数式接口: 有且只有一个抽象方法的接口 FunctionnalInterface注解 常见的函数式接口 Runnable / CallableSupplier / ConsumerComparatorPredicateFunction 二、代码实现 1、Runnable - RunnableLambda测试类 package tech.flygo.…

VSCode编辑器下载与安装

1、下载 官网下载地址&#xff1a; 打开下载地址&#xff0c;如下图&#xff0c;根据自己的平台选择相应版本下载&#xff08;本文只针对Windows系统的安装&#xff0c;所以下载Windows版的&#xff09;。 点击会自动下载&#xff0c;下载完成文件如下图&#xff1a; 2、安装…

超实用的小红书达人投放策略分析,纯干货

为什么我投放了小红书达人却没有什么效果&#xff1f; 品牌到底应该怎么投放小红书达人&#xff1f; 品牌小红书达人投放怎么去把控和规划&#xff1f; 小红书达人作为品牌方和用户之间的桥梁&#xff0c;直接影响消费决策。达人粉丝数量大&#xff0c;粘性高&#xff0c;很…

市场复盘总结 20240104

仅用于记录当天的市场情况,用于统计交易策略的适用情况,以便程序回测 短线核心:不参与任何级别的调整 昨日回顾: 方法一:指标选股 select * from dbo.ResultAll where 入选类型 like %指标选股% and 入选日期=20240104;方法二:趋势选股法 1、最低价持续3日上涨 2、均价…

CSS transition详解

文章目录 属性transition-propertytransition-durationtransition-timing-functiontransition-delaytransition 简写属性 方法Element&#xff1a;transitionrun 事件Element&#xff1a;transitionstart 事件Element&#xff1a;transitionend 事件Element&#xff1a;transit…

深入探究:使用大型AI模型的实战指南

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在今天的技术领域&#xff0c;大型AI模型已成为…

指增的超额来自于哪里,2024的乾坤九法,美股的宏观估值双杀

图片截止到&#xff1a;2024/1/4 上证 周四 -0.43% 市场热点分析 1. 2024元旦后国内外市场都出现了不同程度的下跌。技术面国内市场一直走在72日均线之下&#xff0c;而且没有形成底部&#xff0c;熊市还会延续。宏观方面&#xff0c;12月官方PMI持续向下&#xff0c;小企业更多…

C++_string类

目录 一、string的模拟实现 1、初始化字符串 2、拷贝构造 3、赋值重载 4、迭代器 5、比较字符串 6、尾插字符、字符串 7、resize 8、中间插入数据、删除数据 8.1 插入数据 8.2 删除数据 9、查找数据 10、打印对象&#xff08;流插入、流提取&#xff09; 结语&a…

【企业动态】Silicon Labs中国区总经理拜访东胜物联,加深合作交流

12月27日&#xff0c;芯科科技(Silicon Labs)中国区总经理周巍先生前来我司拜访&#xff0c;东胜物联CEO支江峰先生热情接待&#xff0c;双方就物联网网关、Beacon等产品合作相关事宜进行交流。 在这次重要的会晤中&#xff0c;双方就技术创新以及未来合作方向进行了深入沟通。…

快手推荐算法工程师三面回顾

快手三次技术面试一次HR面试的简单回顾&#xff0c;希望对大家有所启发。 一面 面试官一上来就让写算法题&#xff0c;第一个是计算岛屿数量&#xff0c;第二个是最长回文字串。 然后就是介绍自己的论文。对于论文的工作&#xff0c;面试官只是在问关于论文的问题&#xff0…

光掩膜基板,到2024年全球市场规模将超过30亿美元

光掩膜基板是一种用于微电子加工的关键材料&#xff0c;其特点是具有高透光性和高平整度&#xff0c;能够提升微电子元器件的成品率和品质。全球市场分析 从全球市场来看&#xff0c;光掩膜基板市场规模持续增长。据分析&#xff0c;到2024年&#xff0c;全球光掩膜基板市场规模…

buuctf-Misc 题目解答分解106-108

106.[DDCTF2018]流量分析 提示了私钥 &#xff0c;无厘头&#xff0c;先不管了&#xff0c;应该是流量加密了&#xff0c;用wireshark 打开 看看&#xff0c;真个数据流量&#xff0c;没有http 直接找到TCP 协议的包追踪一下TCP 找到TCP 不是红色的包追踪&#xff0c;大量的数…

webStorm打开终端Cannot open Local Terminal Failed to start [powershell.exe] in

今天webStorm打开终端显示 Cannot open Local Terminal Failed to start [powershell.exe] in D:\allproject\boosterStation 有关详细信息&#xff0c;请查看 IDE 日志(帮助 | 在 Explorer 中显示日志)。 解决方案&#xff1a; 打开设置&#xff08;如下图&#xff09;&a…

Mysql和Redis数据一致性问题

MySQL和Redis数据一致性算是个很经典的问题,在之前也看到过很多相关的文章,最近心血来潮,想把一致性问题的解决方案和存在问题都总结一下。 不推荐方案 1 先更新MySQL,再更新Redis。 如上图有两个请求要同时进行更新操作,在并发情况下,B请求虽然更新时间晚于A请求,但是…

【docker】如何编写dockerfile文件,构建docker镜像

如何编写dockerfile文件&#xff0c;构建docker镜像 一、docker 镜像与 dockerfile1.1 什么是Docker镜像1.2 Docker 镜像的结构 二、dockerfile 中常用的构建指令三、dockerfile 内容示例四、构建 docker 镜像 一、docker 镜像与 dockerfile 1.1 什么是Docker镜像 Docker镜像…

robots.txt

####什么是robots.txt? ​ robots.txt是一个协议,我们可以把它理解为一个网站的"管家",它会告诉搜索引擎哪些页面可以访问,哪些页面不能访问。也可以规定哪些搜索引擎可以访问我们的网站而哪些搜索引擎不能爬取我们网站的信息等等,是网站管理者指定的"君子协议…