大家好,又见面了,我是全栈君。
看这篇也可以看一下最新整理的文:
Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)
先复制一个面试/笔试的题:
当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
答案:
是值传递。Java语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的。C++和C#中可以通过传引用或传输出参数来改变传入的参数的值,但是在Java中却做不到。
java中的按值传递和按址传递(按引用传递),要明白这两个概念,要理解按值和按址。
下面举个简单的例子来说明:
比如你去国外旅行,拍了一张特别好的照片,你想分享给你的朋友,那么有两种方式,第一种是你直接将这个照片发送给你的朋友,也就是给你朋友这个照片的副本;第二种是假如你将这张及其好的照片上传到一个QQ(微博)等,你将会得到一个访问这个照片的地址(Url),此时在将这个url分享给你的朋友。
如上例子,第一种可以认为是按值传递,第二种可以认为是按址传递(按引用传递)。知道了这个概念。在进行下面的简单分析。
-
按值传递:只有当参数为基本类型变量的时候,java按这种策略的方式传递。
上面的分享照片,你的朋友拿到的照片是你的副本,那么朋友对照片的修改不会影响你的照片,你对照片的修改也不会影响到你给朋友分享的照片。 -
按址传递:只有当参数为引用类型变量,java按这种策略方式进行传递。
上面的Url地址给朋友,那么如果朋友也有修改的权限,朋友对照片进行操作,自己访问的照片就是朋友操作结果后的结果。
下面通过代码来解释这个例子:
package com.dufy.reforvalue;
import java.util.Arrays;
/**
* java中 按值传递和按址传递
* 按值传递:基本类型变量-按值传递,按值传递通过复制获取参数的副本
* 按址传递:引用类型变量-按址传递,按址传递通过传递对象的引用地址
*
* @author dufy
* @creation 2017年2月9日
*/
public class ReferenceOrValue {
/**
* 基本类型,按值传递
* 举例:给朋友分享你的照片,对方接收的是你的照片的一个实际的副本,
* 你和朋友分别对各自的照片进行操作,不会影响彼此的照片!
*/
public static void testVal(int photo){
photo++;//朋友对照片进行修改
System.out.println("My friend see photo = " + photo);
}
/**
* 引用类型:按址传递
* 举例:给朋友分享你的照片,分享的是你上传网上的一个照片的Url(地址),
* 你和朋友都可以通过这个地址访问照片,并对照片进行一个操作!
*/
public static void testRef(Photo photo){
photo.setPhoto("java Photo,Great!");//朋友对你的照片进行修改
System.out.println("My friend see photo = " + photo.getPhoto());
}
/**
* 引用类型:按址传递
* 因为数组是一个引用类型。所以传递进去的是它们的引用,故在方法中互换了它们的值,也必然影响到它们原来的值.
*/
public static void testArrayRef(int[] array){
for (int i = 0; i < array.length; i++) {
array[i] = 0;
}
System.out.println("testArrayRef array is = "+Arrays.toString(array));
}
public static void main(String[] args) {
//一:按值传递
int photo = 10;//定义要发送的照片
testVal(photo);//将照片发发送你朋友,朋友得到的是一个副本
System.out.println("My see photo = " + photo);
//二:按址传递
Photo p = new Photo();//定义一个照片的对象,我自己拍摄的java photo
p.setPhoto("java photo");
testRef(p);//将照片对象(即 Url地址) 发送你朋友,朋友得打的是一个Url(地址),Url打开才是照片
System.out.println("My friend see photo = " + p.getPhoto());
//三:数组也是对象,数组在堆内存。引用是在栈。
int array[] = {1,2,3,4,5};
testArrayRef(array);
System.out.println("array is = "+Arrays.toString(array));
}
/**
* 照片类
*/
static class Photo{
String photo;
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
}
}
输出的结果如下:
My friend see photo = 11
My see photo = 10
My friend see photo = java Photo,Great!
My friend see photo = java Photo,Great!
testArrayRef array is = [0, 0, 0, 0, 0]
array is = [0, 0, 0, 0, 0]
小插曲:有下下面这一道题:这个method应该怎么写呢?
public static void main(String[] args) {
int a = 10;
int b = 20;
method(a,b);//需要在method被调用后,仅打印出a=100,b=200,请写出method(a,b)方法!
System.out.println("a = " + a);
System.out.println("b = " + b);
}
肯定有很多人和我之前一样,想都没想就写出下面的代码:
private static void method(int a, int b) {
a*=10;
b*=10;
}
但是运行结果后你会发现,没有打印出理想的结果!
这时候如果你仔细看来了上面的介绍就不难理解为什么会出现这样的结果了!
给出这道题可能正确的结果:
private static void method(int a, int b) {
System.out.println("a=100,b=200");
System.exit(0);
}
附:
public static void main(String[] args) {
int a = 10;
int b = 20;
method(a,b);//需要在method被调用后,仅打印出a=100,b=200,请写出method(a,b)方法!
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("a = " + Integer.valueOf(a));
System.out.println("b = " + Integer.valueOf(b));
}
private static void method(Integer a, Integer b) {
try {
Field filea = a.getClass().getDeclaredField("value");
filea.setAccessible(true);
filea.setInt(a, 100);
Field fileb = b.getClass().getDeclaredField("value");
fileb.setAccessible(true);
fileb.setInt(b, 200);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void method1(int a, int b) {
System.out.println("a=100,b=200");
System.exit(0);
}
输出结果:
a = 10
b = 20
a = 100
b = 200
你觉得正确的答案是什么,可以给我留言和评论,欢迎讨论!
java到底是值传递还是引用传递? 知乎:https://www.zhihu.com/question/31203609
你会swap吗,按值传递还是按引用?:http://www.cnblogs.com/foreach-break/p/call-by-reference-OR-call-by-value.html
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/121191.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...