为什么说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. Future详解

    Future模式 [1]Future模式是多线程开发中常见的设计模式,它的核心思想是异步调用.对于Future模式来说,它无法立即返回你需要的数据,但是它会返回一个契约,将来你可以凭借这个契约去获取你 ...

  2. cURL error 1014: SSL verify failed 报错

    报错 [ERROR] cURL error 1014: SSL verify failed (see https://curl.haxx.se/libcurl/c/libcurl-errors.htm ...

  3. 后端框架的学习----mybatis框架(7、使用注解开发)

    7.使用注解开发 1.注解在接口上实现 /** * 查询用户 */ @Select("select * from user") public List<User> ge ...

  4. JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符

    文章目录 1.强制类型转换Number 1.1 代码 1.2 测试结果 2.进制表示 2.1 代码 2.2 测试结果 3.强制类型转换为Boolea 3.1 代码 3.2 测试结果 4.运算符 4.1 ...

  5. Optimize(优化实验)

    十大优化法则 1.更快(本课程重点!) 2.更省(存储空间.运行空间) 3.更美(UI 交互) 4.更正确(本课程重点!各种条件下) 5.更可靠 6.可移植 7.更强大(功能) 8.更方便(使用) 9 ...

  6. Windows7下驱动开发与调试体系构建——3.调试体系概述

    目录/参考资料:https://www.cnblogs.com/railgunRG/p/14412321.html 调试体系概述 0.什么是自建调试体系? 就是复写windows的调试api,使得调试 ...

  7. Vue报错:component has been registered but not used

    原因: ​​eslint​​代码检查到你注册了组件但没有使用,然后就报错了.比如代码: 比如​​Vue​​​中注册了​​File​​组件,而实际上却没有使用到(直接取消注册为好): ... impor ...

  8. Terminal(oh-my-zsh) 美化

    如果你使用Mac进行开发,那么Terminal.app应该是你使用非常频繁的app了.初体验Terminal时你可能觉得单调乏味,阅读密密麻麻的内容也很费劲.但是如果你跟着我一起配置它,就会发现你平时 ...

  9. MLP(SGD or Adam) Perceptron Neural Network Working by Pytorch(including data preprocessing)

    通过MLP多层感知机神经网络训练模型,使之能够根据sonar的六十个特征成功预测物体是金属还是石头.由于是简单的linearr线性仿射层,所以网络模型的匹配度并不高. 这是我的第一篇随笔,就拿这个来练 ...

  10. 定制ASP.NET Core的身份认证

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 在本章,我们将学习如何定制ASP.NET Core认证机制.微软把安全认证当做AS ...