首先用三句话来总结,后面再做解释:
1.对象就是传引用,对对象的改变直接是改变的应用指向的对象。方法内对对象的改变直接影响到方法外的对象。
2.原始类型就是传值,传的是值得副本,对副本的改变不会影响原始的值。方法内对传值的改变不会影响方法外的值。
3.String等immutable类型因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待。可以认为是传值。
下面程序的输出是什么?
image如果你的回答是“小强”,好,恭喜你答对了。下面我们改一下代码:
image是的,我只是在changeName方法里面加了一句代码
image这一次的输出又是什么呢?
-
A旺财
-
B小强
答案是 A旺财,changeName方法并没有把myDog的名称改了。如果你答错了,没关系,我要开始画小狗了,画完你就明白了;如果你答对了,但不太明白其中的原因,那我画的小狗也肯定能帮到你。
myDog是什么
首先你要搞懂,代码里的变量myDog是什么?myDog真的就是一只狗吗?不!不是!myDog只是一条遛狗用的狗绳!
image换句话说说,myDog并不是new出来的放在堆中的对象(object)!myDog只是一个指向这个对象实例的引用(reference)!如果你对Java的运行时数据区域足够了解,应该知道,这个引用是放在虚拟机栈上的。
参数传递
现在你知道了,myDog只是一条绳子,但这似乎并不能解释为什么changeName方法没有把myDog的名称改为“小强”,因为按照现有的理解,dog = new Dog(),就是把我的狗绳绑到另一只小狗身上,然后给这只小狗起名为“小强”,就像这样:
image可事实是,myDog还是叫旺财,这是为什么?
问题就出在方法调用上,当我执行changeName(myDog)这一行代码时,myDog这条狗绳,被复制了一份,而传入到changeName方法里的那条狗绳(dog),就是复制出来的那一条,就像这样:
接着执行dog= new Dog(),这一行代码,就是把复制出来的那一条狗绳,从myDog解绑,重新绑到new出来的那只小狗上,也就是后来被起名为“小强”的小狗:
image而myDog还是绑在旺财身上,这也就解释了,为什么执行完方法出来,myDog.getName()还是旺财。而在第一段代码里面,我们没有执行dog= new Dog(),也就没有改变dog所绑的小狗,dog还是绑在旺财身上,因此dog.setName(“小强”) 就把旺财的名字改成小强了。
string的例子
我们再来看一个例子:
image如果你弄懂了上面那个例子,那么这里应该不难理解,changeString方法里,只是将新复制出来的引用str,指向另外一个字符串常量对象“bbb”,方法体外面的str并不受影响,还是指向字符串常量“aaa”,因此最终打印的还是aaa.
int的例子
上面提到的都是对象,下面看一个基本数据类型的例子
image对于基本数据类型,他们没有引用,但是不要忘了,调用函数时,复制的动作还是会做的,执行changeInt(i)时,会将 i 复制到一个新的int上,传给changeInt方法,因此不管changeInt内部对入参做了什么,外面的 i 都不会受影响。最后打印出来的还是1.
Java的变量都不是对象
通过上面的讲解,你也知道了一个很重要的点:Java里面的变量,要么是基本数据类型,要么是指向对象实例的引用类型(狗绳),绝对不会是一个对象(狗)。
参考网络的一篇文章
网友评论