校招季,本人匆匆忙忙地参加各种宣讲会,几次笔试下来都遇到同一个题目,而且全都错在同一想法上,方知自己的基础实在不太牢固,因此特别写在博客上提醒自己要脚踏实地地学习!不多说了,题目如下:

 public class Test {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("a");
StringBuffer s2 = new StringBuffer("b");
change(s1, s2);
System.out.println(s1);
System.out.println(s2);
} private static void change(StringBuffer s1, StringBuffer s2) {
s1.append(s2);
s2=s1;
}
}

问题:请问最后打印出的结果是什么?

如果阅读我这篇随笔的是刚接触java(c#也行,java和C#在这方面基本一致)的同学,不妨不看后面的答案,自己做一下,也许会给你带来一些收获!


我在笔试的时候有四个选项:

A.a,b    B.ab,b    C.a,ab    D.ab,ab

很可能有不少人都会和我一样直接选择了选项D,不过很抱歉,这是一个绝对错误的答案,正确的答案是  B   选项。

是不是也会有人和我刚开始一样觉得很奇怪呢?因为根据我们学到的知识,StringBuffer类型的变量是引用类型,也就意味着这个变量在change方法中的改变是会被保留下来的,那么s1,s2在change方法中都被改变了,为什么最后打印的时候只有s1是真正被改变了呢?

这个需要先知道一些基本的知识:

我们都知道在java中有基本数据类型和引用数据类型,他们在内存中的存储是不同的,基本数据类型诸如int,double之类的变量是直接把值存放在栈中的,而引用数据类型的变量是分为两部分进行存储的:第一部分和基本数据类型一致是存放在栈中的,第二部分是堆中。其中堆中存放的是这个变量真正的值,而栈中则是存放真正值的地址,就上面的题目来说,示意图如下:

图一

好了,如果知道变量的存储方式的话就可以往下了(如果不知道建议看看这方面专门的文章,我这篇说的不细)。

change方法中的参数名也是这题的障碍所在,因为名字和变量相同,会让人很容易进入陷阱,误认change方法中的参数s1,s1就是main方法中的变量s1,s2,我们不妨把参数名改一下,改后的代码如下:

 public class Test {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("a");
StringBuffer s2 = new StringBuffer("b");
change(s1, s2);
System.out.println(s1);
System.out.println(s2);
} private static void change(StringBuffer a, StringBuffer b) {
a.append(b);
b=a;
}
}

注意第10行红色加粗的参数名,这样我们就可以绕开一点障眼法。

其实在这题中还是有个小问题的,那就是java中到底有没有引用传递的问题,如果是基本数据类型的话,如

 int x=10;

 print(x);

 public void print(int y){
System.out.println(y++);
}

此时x作为print方法的参数,传递的是x真正的值,我们很容易知道在print方法中y的值是x值的复制,也就是说变量x只是把自己的值拷贝了一份给另外一个局部变量y,实质上二者没有任何关系,无论在print方法中y如何变化都不会影响x的值,这就是值传递了。而如果int x,y的类型改为Integer,此时变量都变为引用类型,x作为参数传递的就是x值的地址,那么y值在print方法中的改变就会反映到x的改变,这就是引用传递。

仔细想想,值传递和引用传递其实传递的都是作为参数的直接值(引用类型变量的直接值是真正值的地址),因此实质上说java只有值传递更为恰当。

解决了这个比较主观的问题之后,我们再来研究一下,引用类型变量s1,s2把地址传递给change方法之后,局部变量a,b就成为了s1,s2的别名(拥有相同的地址,指向了同一实例对象,只是名称不同而已,就和爸妈与老师叫你的称呼不一样),s1追加了s2的内容,所以变量s1的变化会被保留下来,最终打印的结果自然是“ab”,没有疑问。

重点来了,执行“a=b;”进行了变量的什么操作呢?

图二

这样就可以清晰地看到,"b=a"这个操作实质只是把局部变量a的直接值(也就是真正值的地址)赋给了变量b,对于变量b的真正值没有任何的操作,所以对应变量s2的真正值没有任何变化,自然最后打印出来的结果是 “b".

java初步—参数的值传递的更多相关文章

  1. Java 参数传递都是值传递

    Java 参数传递都是值传递,验证代码如下 public class ParamTransferTest { public static void swap(int a, int b) { int t ...

  2. java 传参方式--值传递还是引用传递

    java 传参方式--值传递还是引用传递 参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递.写它是为了揭穿普遍存在的一种神话,即认为 Java 应用程序按引用 ...

  3. Java中到底是值传递还是引用传递?

    Java中到底是值传递还是引用传递? 我们先回顾一下基本概念 实参和形参 参数在编程语言中是执行程序需要的数据,这个数据一般保存在变量中.在Java中定义一个方法时,可以定义一些参数, 举个例子: p ...

  4. Java中真的只有值传递么?

    Java中真的只有值传递么? (本文非引战或diss,只是说出自己的理解,欢迎摆正心态观看或探讨) 回顾值传递和引用传递 关于Java是值传递还是引用传递,网上有不一样的说法. 1.基本类型或基本类型 ...

  5. Java传参:值传递 or 引用传递 ?

    刚开始学Java的时候一度以为:基本数据类型是值传递,引用类型是引用传递.新人很容易在这两个概念上面被搞糊涂,后来看了Hollis的文章才明白了Java中只有值传递. 接下来我能用简单明了的方式来说明 ...

  6. 面试题:Java中为什么只有值传递?

    作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA底层.面试相关资料等更多精彩文章在公众号「小牛呼噜噜 」 目录 经典的问题 形参&实参 Java是 ...

  7. java函数参数默认值

    java函数参数默认值 今天,需要设定java函数参数的默认值,发现按照其它语言中的方法行不通 java中似乎只能通过函数的重载来实现 函数参数默认代码

  8. Java面向对象-方法的值传递和引用传递

    Java面向对象-方法的值传递和引用传递 0 发布时间:『 2016-08-21 14:21』  博客类别:Java核心基础  阅读(197) 评论(0) Java面向对象-方法的值传递和引用传递 方 ...

  9. 深入理解python中函数传递参数是值传递还是引用传递

    深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是"传对象引用 ...

随机推荐

  1. Redis-事务即简单锁应用

    Redis支持简单的事务, Redis允许一组命令在单一步骤中执行, 事务有两个属性 事务是一个单独的隔离操作, 事务中所有的命令都会序列化, 按照顺序执行. Redis事务是原子性的, 即要么都执行 ...

  2. 39. leetcode 326. Power of Three

    326. Power of Three Given an integer, write a function to determine if it is a power of three. Follo ...

  3. 利用Apache commons-net 包进行FTP文件和文件夹的上传与下载

    首先声明:这段代码是我在网上胡乱找的,调试后可用. 需要提前导入jar包,我导入的是:commons-net-3.0.1,在网上可以下载到.以下为源码,其中文件夹的下载存在问题:FTPFile[] a ...

  4. CSS3伪类实现动画旋转效果

    一个简单的动画效果demo,keyframes为关键帧,图片贴在代码下方.利用了伪类实现css3动画效果,初学者可以看一下,恩.<!doctype html> <html lang= ...

  5. 有关cxf与安卓客户端或者C客户端的中文乱码问题

    前段时间在与C的客户端和安卓的客户端进行联调,首先我的方法接收的是C客户端所传递的数据,但是传递到方法内的中文就变成了乱码(我的方法的编码是utf8),最后通过String a = new Strin ...

  6. NET中解决KafKa多线程发送多主题的问题

    一般在KafKa消费程序中消费可以设置多个主题,那在同一程序中需要向KafKa发送不同主题的消息,如异常需要发到异常主题,正常的发送到正常的主题,这时候就需要实例化多个主题,然后逐个发送. 在NET中 ...

  7. java中使用poi导出excel表格数据并且可以手动修改导出路径

    在我们开发项目中,很多时候会提出这样的需求:将前端的某某数据以excel表格导出,今天就给大家写一个简单的模板. 这里我们选择使用poi导出excel: 第一步:导入需要的jar包到 lib 文件夹下

  8. 敏捷视界:Scrum起源、Scrum术语

    Scrum起源 Scrum的原始含义 Scrum原始含义是指英式橄榄球次要犯规时在犯规地点对阵争球.争球双方各有8个队员参与,各方出3名前锋队员,并肩各站成一横排,面对面躬身互相顶肩,中间形成一条通道 ...

  9. python实战===实现读取txt每一行的操作,账号密码

    最近搞到了一批163邮箱的账号和密码,但是里面有部分账号不能用,密码是错的. 以此为背景 人工手动挨个登录检查效率太低! 于是写了下面这个脚本: import linecache import smt ...

  10. jQuery.extend 使用函数

    介绍 jQuery.extend([deep], target, object1, [objectN])用一个或多个其他对象来扩展一个对象,返回被扩展的对象.如果不指定target,则给jQuery对 ...