java中对象作为参数传递给一个方法,到底是值传递,还是引用传递?

String和int参数传递是按值传递还是引用传递?

一道面试题目,String的传递:

public String change(String s){
s = "222";
return s;
}
public static void main(Stirng[] args){
String s = "111";
change(s);
sout(s);
}

我看到题目愣了一下,本来不假思考的结果是111,但仔细想,String是对象类型的,对象传递的是地址,那么地址传递到方法里面后,将指向修改成222,那么结果应该是222才对。实际恰恰相反。

Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。

java传递参数都是值,如果是对象的话,就是将引用的值复制一份给方法当参数。如果是根据引用把堆里的对象修改了,那么对象真被修改了,不过不是被创建赋值给的那个引用修改的,是方法里的一个复制的引用副本给修改的。换句话说,施瓦星格的媳被施瓦星格的克隆人亲了下。

用实例去理解,其实这个理解也就是根据jdk的结果告诉我自己记住规则是这样的,以后要记住。

  public String change(String s, int i, StringBuffer sb, Person p){
s="123";
i=3;
sb.append("woshi");
p.setAge(100);
sb = new StringBuffer("sbsb");
p = new Person("bb",44);
return s;
} @Test
public void testChange(){
StringBuffer sb = new StringBuffer("buff");
String s = "aaa";
int i = 1;
Person p = new Person("aa",12);
i=2;
change(s,i,sb,p);
// s="222";
System.out.println(s);
System.out.println(i);
System.out.println(sb.toString());
System.out.println(p);
}

这里一共测试了String,int,一个对象StringBuffer,一个对象people。让我们来仔细看看这些传递都发生了什么。我想有很大一部分人都猜不出打印结果。

aaa
2
buffwoshi
Person{id=0, name='aa', age=100, Country=null, hashcode=638783031}

我们来一个个分析。

首先是String。

String s = "aaa";

这里,jvm创建一个变量引用s,在堆中创建一个对象aaa,将aaa放进常量池。s指向aaa。

然后就到了change方法里。这里这样理解:将s引用的一个拷贝传给方法change。这样change有一个变量s,这个s也是指向aaa的。那么我们来通过debug来看后来发生了什么。

1.s指向aaa的时候:

2.s运行到change方法里的时候

然后看s再次赋值的时候:

然后我们运行结束change方法后到主方法里:

到这里s就结束了。那么如果我们按照传递的是s这个变量的引用,即String s="aaa"中这个s本身,那么,s这个本身是个变量,s指向aaa,在方法change里s又指向了123,回到主方法后s变量的指向被改变了?错!显然s仍旧是aaa,那么只能这样理解:s传递到方法里的时候,复制了s指向的地址给change,change里的s是另一个s,s指向aaa(@718),然后在change中s又指向了123(@731),由于String是不可变类(final and Immutable),这里只是把副本s的指向修改成731,原地址718里的对象没有发生改变因为String不可变。那么,回到主方法的时候,s变量本身没有任何改变,s仍旧指向地址718,718的内容是aaa。所以最终打印aaa。

然后是StringBuffer

int是基本类型,所以int只是将值复制一份给别的方法用,这个大家都知道,就不去测试了。现在看StringBuffer发生的改变。

1.初始化:

2.到change方法中:

3.发生append

4.指向新对象

这里就要说一下了,副本指向了新对象。就好比,施瓦星格的克隆人找了另一个女的当老婆,而真正的施瓦星格老婆没有变。

5.回到主方法:

到这里,StringBuffer就结束了。我们必须知道,虽然我们没有去研究源码是怎样实现的,change方法得到是一个sb的副本,只不过这个副本指向708,在change里对708的对象追加,708的对象就真的改变了。然后又把sb副本指向新地址737。这只是把副本指向的地址修改了,如果你在这里打印sb.toString(),打印的就是737里的内容。当跳出change,回到主方法的时候,原sb仍旧还是指向708的,最终就是打印708的结果。和String不同的是,StringBuffer的结果发生了变量,因为StringBuffer是可变的,可以append。而String是不可变的,在change中s=123就是发生两个行为,一个是查找常量池中是否有123,如果没有就在堆中创建123,一个是将s指向123.也就是说这时候是创建了一个新的String对象,而不是把原来的String对象s内容修改。这样,回到主方法的时候,s仍旧是aaa。

同理,看自己创建的对象people

1.初始化:

2.p传递到change里的时候

3.p副本设置age

4.p副本重新赋值

这里仍旧要说一下,p副本修改了自己指向,并不影响主方法里的p的指向。主方法里的p的指向没有发生变化,依旧应该还是720.

5.回到主方法

总结:

通过上面对String,StringBuffer,People的研究,应该明白一个道理,重要的话说三遍,重要的规则我都演示了三遍。如果跟着步骤一步步走的,肯定牢记住了:

java所有的参数传递都是传递的副本,变量所代表的值的副本!java所有的参数传递都是传递的副本,变量所代表的值的副本!java所有的参数传递都是传递的副本,变量所代表的值的副本!

这里必须记住的就是副本概念。在方法里,运行的时候到这里的线程都会把传过来的参数拷贝副本带自己的工作区中,在工作区中对这个副本的值发生一些改变。最终改变的是副本,如果通过副本的指向修改了指向中的内容,那么那个指向的地址里的内容确实改变了。如果修改了副本的指向,即给副本重新赋值,那么关原来的变量何事?元变量仍旧指向最初的地址。

那么,String传递过去的是副本,修改了副本的指向,打印元string是不会改变的,因为副本没有能力修改final的String类。

String的按值传递,java传参都是传值的更多相关文章

  1. Java传参都是传引用变量的副本

    最近做练习时碰到一个问题,Java到底是怎样传参的,经过查资料与实验,我发现Java传参都是传引用变量的副本值. 1 Java中的引用变量 1.1 字面值引用变量:即基本数据类型的引用变量 ,如 in ...

  2. Java传参那些事!

    刚刚学习java传参的时候很纠结,也非常的不理解!课本上的“按值传递”和“按址传递”搞的自己是一头雾水,后来写的项目多了,自然就明白了! 现在写传参几乎就是条件反射一般——“秒成”,分享当初自己为此写 ...

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

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

  4. Java传参

    1.  如果参数是基本数据类型(int.long等),传值.方法内部改变参数值,外部值不变. 2.  如果参数是对象类型,传地址.方法内部改变对象值,外部对象值改变.但是,如果方法内部调用new重新构 ...

  5. 深入分析java传参

    概述      java中的参数传递问题可以根据参数的类型大致可以分为三类:传递基本类型,传递String类型,传递引用类型,至于最终是否可以归纳为值传递和引用传递,根据每个人的理解不同,答案不同,此 ...

  6. 使用java传参调用exe并且获取程序进度和返回结果的一种方法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在某个项目中需要考虑使用java后台调用由C#编写的切图程序( ...

  7. Java传参-基本数据类型和引用数据类型作为参数的区别(值传递)

    java中的方法可以传递参数,参数的传递方法就是值传递. 参数有形参和实参,定义方法时写的参数叫形参,真正调用方法时,传递的参数叫实参. 调用方法时,会把实参传递给形参,方法内部其实是在使用形参. 所 ...

  8. java传参问题

    参考链接:https://www.cnblogs.com/linkstar/p/5951141.html public class Example { String testString = publ ...

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

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

随机推荐

  1. SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/D:/MyEclipseWorkSpace/Emps/WebRoot/WEB-INF/lib/slf4j-nop-1.5.6.

    错误的是HQL语句,注意写类名属性名无误,条件无误.

  2. XMPP iOS客户端实现三:登录、注册

    1.创建一个单例模式来管理xmpp的连接和操作 +(XMPPManager *)share { static XMPPManager *_share=nil; static dispatch_once ...

  3. ORACLE冷备份与恢复

    ORACLE备份和恢复有三种方式: (1)数据泵(expdp/impdp) (2)冷备份 (3)RMAN备份 就分类而言,(1)和(2)统有称为"冷"备份,(3)称为"热 ...

  4. SQL Server 2016中In-Memory OLTP继CTP3之后的新改进

    SQL Server 2016中In-Memory OLTP继CTP3之后的新改进 转译自:https://blogs.msdn.microsoft.com/sqlserverstorageengin ...

  5. 减小ipa体积之删除frameWork中无用mach-O文件

    最近项目末期, 我们团队为了ipa的大小使用不少的体积减小的方法, 除了一些常规的方法之外, 我分享一下自己研究出来的新思路. 首先我们来简单的介绍一下mach-O. 什么是mach-O? Mach- ...

  6. Linux下的.NET之旅:第一站,CentOS+Mono+Xsp构建最简单的ASP.NET服务器

    一.Mono产生的背景 由于Linux/Unix等有更强的安全性.运行效率高.拥有大量优秀的开源组件,而.Net则有着其他语言无与伦比的开发效率,因此在非微软平台下运行.Net程序的需求很强烈.Mon ...

  7. HTML5特性速记图

    今天推荐大家一张HTML5特性速记图,供大家平时查阅,也可以打印放在电脑旁帮助速记.速查.此图笔者收集于网络图片.

  8. 链表&LRU

    简介 链表就是链式存储数据的一种数据结构.双向链表每个数据存储都包含他的前后数据节点的位置信息(索引/指针). class DSChain<T> { //使用栈来进行废弃空间回收 priv ...

  9. “安装项目” Step By Step

    目录 一 基本操作 二 定制安装对话框 三 安装程序类 四 总结 .NET程序集因为包含了元数据,所以程序集具有自描述性.多数程序自身包含了运行所需要的全部信息,这类程序集就是我们常说的“绿色软件”. ...

  10. struts2 标签怪事

    <s:if test="4 ge 3">111</s:if><s:else>222</s:else> 结果竟然是222 难道不是 4 ...