Java求值策略
为什么说Java不存在引用传递?
在Java语言中,存在两种数据类型,一种是基本类型,如int、byte等8种基本类型,一种是引用类型,如String、Integer等。这两种数据类型区别就在于,基本类型的各个类型大小是固定的,如int类型占4个字节,且数据存储于栈中;而引用类型大小则不固定,根据引用类型的属性构成决定的,且数据存储是在堆中,栈中的变量存储是指向堆中的数据引用;

正是因为有两种数据的存储区别,很多人才容易将值传递和引用传递搞混了。并且容易产生误解,Java数据如果是基本类型就是值传递,如果是对象(引用类型)那就是引用传递,但这是错误的!
值传递和引用传递
在程序语言中是这样定义值传递和引用传递的:
值传递:是在调用函数时将实际参数复制一份到函数中,这样如果对参数进行修改,将不会影响到实际的参数。
引用传递:是指在调用函数时将实际参数地址直接传递到函数中,那么如果函数中对参数进行修改,将影响到实际的参数。
对于上述概念是程序语言中对于值传递和引用传递的通用概念,那我们用代码来验证一下为何说Java是不存在引用传递的。
首先看基本类型的传递

这段代码最后输出是:

这个结果是毫无疑问的,分别输出的pvb是100和1!即使调用了passByValue(int pbV),在方法中改变了pbV的值,但是在main方法中的pbV的值仍然是1,这说明传入passByValue方法的是个拷贝的副本值,在方法中对这个副本值进行修改,不会影响到原变量,证实Java基本类型是值传递!
再换成引用类型的看看:

大家猜猜最后会输出什么......如果按照值传递的理论概念,传递给函数的变量应该是拷贝的副本,无论在方法函数中做出什么样的修改,都不会影响到原值,所以按照值传递是不是应该输出两个“Java”字符串?!
但事实上最后输出结果却是“Java”和“Java+python”两个字符串:

难道Java是存在引用传递的?
答案是不存在的!我们来分析上面的程序在内存中的存储:

首先在main方法中创建一个StringBuffter对象,此时buffter变量引用此对象的地址,然后调用passByReference方法,此时,将buffter变量引用的地址拷贝一份副本传入passByReference方法,在passByReference中调用引用对象的append(“+python”)方法,此对象变成了”Java+python”字符串,最后输出main方法输出buffer变量所指向的对象,即”Java+python”字符串;
话说回来,将引用拷贝一份副本传至方法参数中,难道这不算引用传递吗?当然不算!
我们再来读一下引用传递的概念定义:引用传递是指在调用函数时将实际参数地址直接传递到函数中,那么如果函数中对参数进行修改,将影响到实际的参数。
事实上,在Java语言中,我们是不能直接获取到实际参数的地址的,我们所使用的都是引用去操作其指向的地址的对象,引用≠实际参数地址,所以在Java语言中不存在引用传递。只是因为在传递引用类型的对象时,拷贝对应的引用值副本进行传参,很多人误以为这就是引用传递,但这其实是值传递。
结论
在Java语言中无论是基本数据类型还是引用类型,都是使用值传递的方式,对于引用传递来说是不存在的。
那最后上一个“硬菜”,下面的这段代码为什么会输出两个一模一样的"Java"字符串呢!如果了解String类型底层的朋友,答案一眼就能看出了,欢迎评论留言。


public class MemberServiceImpl{
void test (int i){
i=3;
}
void testObj (Test test){
test=new Test();
System.out.println(test.getI());
}
public static void main(String[] args) {
MemberServiceImpl memberService=new MemberServiceImpl();
int i=0;
memberService.test(i);
System.out.println("i:"+i);
Test test=new Test();
test.setI(111);
memberService.testObj(test);
System.out.println(test.getI());
}
}
运行结果:
i:0
null
111(之所以不是null是因为,testObj方法内外的引用不是同一个,如果不修改引用指向的对象,则操作的是同一个对象)
Java求值策略的更多相关文章
- 深入理解JavaScript系列(19):求值策略(Evaluation strategy)
介绍 本章,我们将讲解在ECMAScript向函数function传递参数的策略. 计算机科学里对这种策略一般称为“evaluation strategy”(大叔注:有的人说翻译成求值策略,有的人翻译 ...
- Scala - 快速学习04 - 求值策略
表达式求值策略(Evaluation Strategy) Scala中所有的运算都是基于表达式的. Call By Value - 对函数实参求值,且仅求值一次:函数调用之前对所有表达式进行求值 Ca ...
- Scala基础篇-05求值策略
Scala的求值策略有2种: call by value call by name 如何区分? 例子: def bar(x:Int,y: => Int) = def loop(): Int=lo ...
- 关于java是值传递还是引用传递
一.概念 实际上对这两种传递方式,知乎上有个回答说得很好: 值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值和传值的方式的描述,而非传递 ...
- C#函数式编程之惰性求值
惰性求值 在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体会的明白为什么需要利用这个技术.首先需要说明的是C#语言小部分采用了非严格求值策略,大部 ...
- C 语言 - 逻辑运算和短路求值
逻辑运算符: 运算符 含义 优先级 ! 逻辑非 高 && 逻辑与 中 || 逻辑或 低 举例: !a:如果 a 为真,!a 为假:如果 a 为 假,!a 为真 a && ...
- Java 计算数学表达式(字符串解析求值工具)
Java字符串转换成算术表达式计算并输出结果,通过这个工具可以直接对字符串形式的算术表达式进行运算,并且使用非常简单. 这个工具中包含两个类 Calculator 和 ArithHelper Calc ...
- 利用栈实现算术表达式求值(Java语言描述)
利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...
- java实现算术表达式求值
需要根据配置的表达式(例如:5+12*(3+5)/7.0)计算出相应的结果,因此使用java中的栈利用后缀表达式的方式实现该工具类. 后缀表达式就是将操作符放在操作数的后面展示的方式,例如:3+2 后 ...
- 奇怪的表达式求值 (java实现)
题目参考:http://blog.csdn.net/fuxuemingzhu/article/details/68484749 问题描述; 题目描述: 常规的表达式求值,我们都会根据计算的优先级来计算 ...
随机推荐
- .NET平台下一个你不知道的框架,我只想说两个字:“牛逼”
框架内容 零度框架是一套基于微服务和领域模型驱动设计的企业级快速开发框架,基于微软 .NET 6 + React 最新技术栈构建,容器化微服务最佳实践,零度框架的搭建以开发简单,多屏体验,前后端分离, ...
- 一篇文章带你掌握主流办公框架——SpringBoot
一篇文章带你掌握主流办公框架--SpringBoot 在之前的文章中我们已经学习了SSM的全部内容以及相关整合 SSM是Spring的产品,主要用来简化开发,但我们现在所介绍的这款框架--Spring ...
- 小程序返回上一级页面背景音乐报错 setBackgroundAudioState:fail title is nil!;
小程序初始化在onLoad的时候加载了一次背景音乐. 如果此时报错是title必传.如果没有 会报错一次 setBackgroundAudioState:fail title is nil!; 这个都 ...
- C#中ref和out关键字的应用以及区别(参数修饰符)
ref ref的定义 ref是reference的缩写,通过引用来传递参数的地址,ref基本上是服务于值类型的 ref的使用 //不使用 ref; void Method(int myRefInt) ...
- ES6 学习笔记(五)基本类型Boolean
Boolean 1.需要注意的地方: 取值:true false 对于值为空字符串,0,-0,NaN,Null,undefined,false的布尔对象,它都会有一个初始值false.对于其它的值如& ...
- linux下搭建oh-my-zsh环境
目标:因为用习惯了zsh的shell环境,所以习惯在服务器上也搭建zsh环境,但是每次搭建都需要Google每一步骤,感觉很麻烦,所以决定记录一下,免得一次次查 1. 安装zsh zsh是一款shel ...
- Java 多线程写zip文件遇到的错误 write beyond end of stream!
最近在写一个大量小文件直接压缩到一个zip的需求,由于zip中的entry每一个都是独立的,不需要追加写入,也就是一个entry文件,写一个内容, 因此直接使用了多线程来处理,结果就翻车了,代码给出了 ...
- dockerNginx代理本地目录
dockerNginx代理本地目录 ssl_certificate cert/5900588_test.zk.limengkai.work.pem; ssl_certificate_key cert/ ...
- 2022春每日一题:Day 17
今天打CF去了,但是很菜,只做了三题.赛后一分钟做出了第四题,wa了,改了一下下,过了 第一题就是对应的小写字母在大写字母前出现. 第二题直接dfs. 第三题dp,f[i][j]表示以第i个数开始加了 ...
- DevOps 必备的 Kubernetes 安全清单
Kubernetes 是当今许多公司采用的容器编排平台,它的实施需要对其生态系统有一定的了解,以便部署一个准备好用于生产的集群.然而从原则上来说,Kubernetes 并不是一个安全的平台,因为它缺乏 ...