为什么说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求值策略的更多相关文章

  1. 深入理解JavaScript系列(19):求值策略(Evaluation strategy)

    介绍 本章,我们将讲解在ECMAScript向函数function传递参数的策略. 计算机科学里对这种策略一般称为“evaluation strategy”(大叔注:有的人说翻译成求值策略,有的人翻译 ...

  2. Scala - 快速学习04 - 求值策略

    表达式求值策略(Evaluation Strategy) Scala中所有的运算都是基于表达式的. Call By Value - 对函数实参求值,且仅求值一次:函数调用之前对所有表达式进行求值 Ca ...

  3. Scala基础篇-05求值策略

    Scala的求值策略有2种: call by value call by name 如何区分? 例子: def bar(x:Int,y: => Int) = def loop(): Int=lo ...

  4. 关于java是值传递还是引用传递

    一.概念 实际上对这两种传递方式,知乎上有个回答说得很好: 值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值和传值的方式的描述,而非传递 ...

  5. C#函数式编程之惰性求值

    惰性求值 在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体会的明白为什么需要利用这个技术.首先需要说明的是C#语言小部分采用了非严格求值策略,大部 ...

  6. C 语言 - 逻辑运算和短路求值

    逻辑运算符: 运算符 含义 优先级 ! 逻辑非 高 && 逻辑与 中 || 逻辑或 低 举例: !a:如果 a 为真,!a 为假:如果 a 为 假,!a 为真 a && ...

  7. Java 计算数学表达式(字符串解析求值工具)

    Java字符串转换成算术表达式计算并输出结果,通过这个工具可以直接对字符串形式的算术表达式进行运算,并且使用非常简单. 这个工具中包含两个类 Calculator 和 ArithHelper Calc ...

  8. 利用栈实现算术表达式求值(Java语言描述)

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

  9. java实现算术表达式求值

    需要根据配置的表达式(例如:5+12*(3+5)/7.0)计算出相应的结果,因此使用java中的栈利用后缀表达式的方式实现该工具类. 后缀表达式就是将操作符放在操作数的后面展示的方式,例如:3+2 后 ...

  10. 奇怪的表达式求值 (java实现)

    题目参考:http://blog.csdn.net/fuxuemingzhu/article/details/68484749 问题描述; 题目描述: 常规的表达式求值,我们都会根据计算的优先级来计算 ...

随机推荐

  1. BigDecimal 用法总结

    转载请注明出处: 目录 1.BigDecimal 简介 2.构造BigDecimal的对象 3.常用方法总结 4.divide方法使用 5.setScale 方法使用 6.BigDecimal 数据库 ...

  2. 使用python制作动图

    利用python制作gif图 引言 当写文章时候,多张图片会影响排版,可以考虑制作gif图 准备 pip install imageio 代码 # This is a sample Python sc ...

  3. vulnhub靶场之RED: 1

    准备: 攻击机:虚拟机kali.本机win10. 靶机:RED: 1,地址我这里设置的桥接,,下载地址:https://download.vulnhub.com/red/Red.ova,下载后直接Vi ...

  4. Xray

    Xray基础操作 代理设置 运行xray.exe xray.exe genca 运行后会生成ca.crt和cr.key 浏览器导入证书 设置代理7777端口 第一次启动 xray 之后,当前目录会生成 ...

  5. Linux 下搭建 HBase 环境

    Linux 下搭建 HBase 环境 作者:Grey 原文地址: 博客园:Linux 下搭建 HBase 环境 CSDN:Linux 下搭建 HBase 环境 前置工作 首先,需要先完成 Linux ...

  6. JavaScript基本语法(函数与对象)

    3.函数 #①内置函数 内置函数:系统已经声明好了可以直接使用的函数. #[1]弹出警告框 alert("警告框内容");   #[2]弹出确认框 用户点击『确定』返回true,点 ...

  7. Python学习笔记----操作字符串

    1.字符串相加.列表相加.列表和字符串不能混着使用 #序列相加 a="hello" b="python" c=a+b print("字符串相加的结果& ...

  8. 一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)

    这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 11.HashMap和HashTable的区别及底层实现 12.ConcurrentHashMap原理简述,jdk7和jd ...

  9. Visual Studio(VS)修改C语言scanf等报错

    1.在程序最前面加:#define_CRT_SECURE_NO_DEPRECATE 2.按照vs规定进行修改,例如把scanf改为scanf_s: 3.在"项目" -> &q ...

  10. 26.ViewSet和action

      在dispatch过程中,下列属性可用于 ViewSet : basename - 根url路径 action - 当前动作类型(例如 list , create ). detail - 用于指示 ...