Java参数传递是传值还是传php引用传值

下次自动登录
现在的位置:
& 综合 & 正文
再一次 – Java的引用传递与值传递
如果函数内引用没有被改变,函数内部的对象被修改将导致外部的对象变化。
如果函数内部引用发生了改变—引用被切断:(B=A,或者引用了 新new的对象),则函数内部的对象修改不会导致外部对象的变化。
可以简单的记为,在初始化时,“=”语句左边的是引用,右边new出来的是对象。在后面的左右都是引用的“=”语句时,左右的引用同时指向了右边引用所指向的对象。
传值意味着传的是副本,不会改变被传递对象本身。传引用既是传内存地址(也可认为是内存地址的副本),如果传递的对象发生了改变,那么被传递的对象也将改变(所有某些场景需要深拷贝)
1、对象是按引用传递的,原始数据类型是按值传递的
2、如果把引用副本也当做是一种“值”(java中一个对象s是什么,同样也是一个指针),对于jvm来说,这个引用(内存地址)也仅仅是一个int型的整数,所以可以认为:Java
应用程序有且仅有的一种参数传递机制,即按值传递。
但是,传值和传引用本来就是两个不同的内容,没必要把两者弄在一起,弄在一起反而更不易理解。
对于一切对象型变量,Java都是传引用的副本。其实传引用副本的实质就是复制指向地址的指针,只不过Java不像C++中有显著的*和&符号。(这里Java和C++不同,在C++中,当参数是引用类型时,传递的是真实引用而不是引用副本)
也就是说,参数传递,如果参数是对象的话,那么此时,传递的是引用。所以如果函数内部(形参)让该参数对象发生变化,外部对象(被传递的参数也会发生变化)。
以代码下来证明3,4在参数的传递中,哪一个是正确的?
3、按值传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的一个副本
4、按引用传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的内存地址,而不是值的副本
首先我们来看看第一点:对象是按引用传递的确实,这一点我想大家没有任何疑问,例如:
class Test01
public static void main(String[] args)
StringBuffer s= new StringBuffer("good");
StringBuffer s2=s;
s2.append(" afternoon.");
System.out.println(s);
对象s和s2指向的是内存中的同一个地址因此指向的也是同一个对象。
如何解释“对象是按引用传递的”的呢?
这里的意思是进行对象赋值操作是传递的是对象的引用,因此对象是按引用传递的,有问题吗?
程序运行的输出是:
good afternoon.
这说明s2和s是同一个对象。所以对象的赋值,是传递的引用,他们的已经绑为一体。
所以反过来,s.append, 最终打印s2,结果依然是一样的:当引用传递(对象赋值)的时候,无论哪一个对象内容反正了改变,另外一个对象也会发生变化,除非某个对象重新建立一个引用(s2 = new StringBuffer())。
这里有一点要澄清的是,这里的传对象其实也是传值,因为对象就是一个指针,这个赋值是指针之间的赋值,因此在java中就将它说成了传引用。(引用是什么?不就是地址吗?地址是什么,不过就是一个整数值)
再看看下面的例子:
class Test02
public static void main(String[] args)
System.out.println(i);
程序的结果是什么?5!!!
这说明什么,原始数据类型是按值传递的,这个按值传递也是指的是进行赋值时的行为。
下一个问题:如果把对象的引用看作内存地址的值,那么Java 应用程序有且仅有的一种参数传递机制,即按值传递.(基本变量传递肯定是值传递)
下面的例子加入了在函数中进行引用赋值的操作,进行之前,先回顾一下Java中,对象与引用的重要概念。
如下表达式:
A a1 = new A();
它代表A是类,a1是引用,a1不是对象,new A()才是对象,a1引用指向new A()这个对象。
在JAVA里,“=”不能被看成是一个赋值语句,它不是在把一个对象赋给另外一个对象,它的执行过程实质上是将右边对象的地址传给了左边的引用,使得左边的引用指向了右边的对象。JAVA表面上看起来没有指针,但它的引用其实质就是一个指针,引用里面存放的并不是对象,而是该对象的地址,使得该引用指向了对象。在JAVA里,“=”语句不应该被翻译成赋值语句,因为它所执行的确实不是一个赋值的过程,而是一个传地址的过程,被译成赋值语句会造成很多误解,译得不准确。
所以当看到"A=B"操作时,要真正理解它为 A→B:A的引用地址变成了B的引用地址。或者说,让A和B都指向同一地址。切忌简单想成A等于B,或者把B的值赋给A。
这样,当函数体中进行引用变换时: A=B, 要考虑:右边的B对应的外部B引用会变,左边的A对应的外部A引用反而不会变:即函数外部B会变(因为B没有被赋予新的引用,所以他对应的值在函数内被改变,而造成了外部B引用也跟着改变[因为对象传递是引用传递]),而外部A引用的打印值不变,是因为在函数内部,A被赋予了新的引用【B】,所以外部A与函数内部A的引用关系被切断,他们指向了不同的对象。
它代表A是类,a2是引用,a2不是对象,a2所指向的对象为空
它代表,a2是引用,a1也是引用,a1所指向的对象的地址传给了a2(传址),使得a2和a1指向了同一对象。
class Test03
public static void main(String[] args)
StringBuffer s= new StringBuffer("good");
StringBuffer s2=new StringBuffer("bad");
test(s,s2);
System.out.println(s);//9
System.out.println(s2);//10
static void test(StringBuffer s,StringBuffer s2) {
System.out.println(s);//1
System.out.println(s2);//2
s2=s;//3 改变s2的引用,使s2指向引用对象s,即s2和s都指向同一对象
s=new StringBuffer("new");//4
/** note: 本来s被new 了新的,引用被切断也不应该被改变外部的s,但是因为s2=s(且s2在函数中没有被赋予新的引用),那么s2的变化* 才导致外部s的变化。* * important: 如果3,4调换顺序,则s的引用被改变成new,且s2指向s相同的新引用new,那么相对于外部引用来说,函数内部的s和s2,他们的引用都发生了变化* 所以外部(main)的打印结果,保持不变。*/
System.out.println(s);//5 s被赋予了新的引用,所以打印新值: new
System.out.println(s2);//6 对象的赋值是引用传递,但关联引用(s2--&s)不会实时变化,所以s2的引用地址还是老的s,这个跟s2=s;s.append("new"), 然后导致s2也
//会被append "new"不一样。
s.append("hahs");//7 此时函数内s, 是newhahs1, 对于外部s来说,这个append不会起作用,因为第4步里,s被重新设置了引用.
s2.append("hahs2");//8 因为s2=s的关系,此时s2.append相当于s.append。且s2指向的是老的s引用地址,则此时,外部s,仍然是good,所以函数执行完毕后s的打
//印是good+ s2.append的值【并没有受到new StringBuffer的影响】
/* 8 等价于s.append("hahs2"), 因为在第3步中这个引用对象被赋予了新的引用:“s”,
等同于切断外部s2和内部s2的 相同引用传递。则引用赋值s2=s的左边s2
* 是被切断的引用,那么外部的s2(原来那个引用对象s2)就和此时的s2毫无关联,他们指向了不同的对象。s也被new了新的引用,所以外部s本该不变,但
* 第8行,因为s2与s已经连为一体(引用赋值),所以s2变化将绑定在老s(外部s)上,因为他们是同一地址。则s2的append,实际上对于外部的s来说,是
* 相当于进行了s.append("hahs2") 的操作
* 所以不论函数里面的s,s2如何变化,都不会影响外部的那个引用对象s2(原来的s2),故调用方法前后的s2没有发生变化。
程序的输出是:
Note:test方法传递的值,所以9,10中,s2 原来的值不变。
Need to think: s为什么变成了goodhah?
对于基本類型和字符串(字符串特殊,因为其是immutable,所以传递字符串的时候,对象作为参数在函数内部发生变化,外部这个对象,是不会变的)是传值,但是对于对象而言,传的是引用,而引用指向的是同一個對象!所以函数外部的s和s2的地址一致(绑定在了一起,操作同一块内存空间),而s2被append了,所以s发生了变化。
【上篇】【下篇】549被浏览88,902分享邀请回答int num = 10;
String str = "hello";
如图所示,num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。二:搞清楚赋值运算符(=)的作用num = 20;
str = "java";
对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉。对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。如上图所示,"hello" 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)三:调用方法时发生了什么?参数传递基本上就是赋值操作。第一个例子:基本类型
void foo(int value) {
value = 100;
foo(num); // num 没有被改变
第二个例子:没有提供改变自身方法的引用类型
void foo(String text) {
text = "windows";
foo(str); // str 也没有被改变
第三个例子:提供了改变自身方法的引用类型
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder.append("4");
foo(sb); // sb 被改变了,变成了"iphone4"。
第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder = new StringBuilder("ipad");
foo(sb); // sb 没有被改变,还是 "iphone"。
重点理解为什么,第三个例子和第四个例子结果不同?下面是第三个例子的图解:builder.append("4")之后下面是第四个例子的图解:builder = new StringBuilder("ipad"); 之后日添加部分内容:这个答案点赞的不少,虽然当时回答时并没有讲的特别详细,今天就稍微多讲一些各种类型数据在内存中的存储方式。从局部变量/方法参数开始讲起:局部变量和方法参数在jvm中的储存方法是相同的,都是在栈上开辟空间来储存的,随着进入方法开辟,退出方法回收。以32位JVM为例,boolean/byte/short/char/int/float以及引用都是分配4字节空间,long/double分配8字节空间。对于每个方法来说,最多占用多少空间是一定的,这在编译时就可以计算好。我们都知道JVM内存模型中有,stack和heap的存在,但是更准确的说,是每个线程都分配一个独享的stack,所有线程共享一个heap。对于每个方法的局部变量来说,是绝对无法被其他方法,甚至其他线程的同一方法所访问到的,更遑论修改。当我们在方法中声明一个 int i = 0,或者 Object obj = null 时,仅仅涉及stack,不影响到heap,当我们 new Object() 时,会在heap中开辟一段内存并初始化Object对象。当我们将这个对象赋予obj变量时,仅仅是stack中代表obj的那4个字节变更为这个对象的地址。数组类型引用和对象:当我们声明一个数组时,如int[] arr = new int[10],因为数组也是对象,arr实际上是引用,stack上仅仅占用4字节空间,new int[10]会在heap中开辟一个数组对象,然后arr指向它。当我们声明一个二维数组时,如 int[][] arr2 = new int[2][4],arr2同样仅在stack中占用4个字节,会在内存中开辟一个长度为2的,类型为int[]的数组,然后arr2指向这个数组。这个数组内部有两个引用(大小为4字节),分别指向两个长度为4的类型为int的数组。所以当我们传递一个数组引用给一个方法时,数组的元素是可以被改变的,但是无法让数组引用指向新的数组。你还可以这样声明:int[][] arr3 = new int[3][],这时内存情况如下图你还可以这样 arr3[0] = new int [5]; arr3[1] = arr2[0];关于String:原本回答中关于String的图解是简化过的,实际上String对象内部仅需要维护三个变量,char[] chars, int startIndex, int length。而chars在某些情况下是可以共用的。但是因为String被设计成为了不可变类型,所以你思考时把String对象简化考虑也是可以的。String str = new String("hello")当然某些JVM实现会把"hello"字面量生成的String对象放到常量池中,而常量池中的对象可以实际分配在heap中,有些实现也许会分配在方法区,当然这对我们理解影响不大。77696 条评论分享收藏感谢收起博客分类:
看了很多Java的模拟笔试题,几乎每套题里都有这么个选择题:Java参数是传值还是传引用。
每次遇到这个选择题我就很郁闷,因为我不明白何为“传值”,何为“传引用”,虽然我确实了解Java参数传递过程中发生了什么。这里我就不因个人的愚来钝混淆视听了,总之,不管是以后这种题以什么形式提出都好,理解Java参数传递过程才是王道。
先看primitive型数据的情况:
public static void tripleValue(double x) //
//call this method
double percent = 10;
tripleValue(percent);
System.out.println("After: percent =" + percent ); // 10
当进入到tripleValue方法中时,x是percent的一个copy,因为percent是primitive的,因此它的copy也是primitive,也就是说x就是一个单纯的值,对这个“值”做操作不会影响方法外面的percent变量的,因此操作完成后percent依然是10。
看object型数据的情况:
public static void tripleSalary(Employee x)
x.riseSalary(200);
Employee harry = new Employee(. . .);
tripleSalary(harry);
System.out.println("After: salary=" + harry.getSalary()); // works
执行这段代码时,当进入到tripleValue方法中后,x是harry的一个copy,harry是指向一个Employee对象实例的引用,因此x也是同样的一个引用。此时,通过x调用Employee对象实例的riseSalary方法,可以修改对象实例的salary值,又因为harry也指向同一对象,因此harry.getSalary()所得值也发生了变化。
但是,切记,x仅是harry的一个copy,在对x做任何操作之前,它们之间的唯一联系仅是指向同一对象,但如果在方法中我们改变了x的指向,那么这个变化是不会影响到harry的。
以上就是Java参数传递的过程。那个选择虽然现在也不明白,但是还是说一下通用的答案比较完整:
Java参数是传值嗒~
浏览: 167718 次
来自: 上海
谢谢作者分享的经验,非常有用!
试下用rs.getObject()
呃,这里被抄袭了。http://www.myexception ...
非常不错,很全面。学习了。
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'博客分类:
记得以前看书,里面说,"Java 是传值还是传引用,问题主要出在对象的传递上,因为 Java 中简单类型没有引用。"看一下下面的例子: public class Pass { String a="123"; public static void test(Pass passA) { passA.a="abc"; } public static void main(String[] args) { Pass passB=new Pass(); passB.a= "123"; System.out.println(passB.a); test(passB); System.out.println(passB.a); } } 结果是: 123 abc 从这个结果来看是通过引用传递的.String不是简单类型,那么是不是也是通过引用来传递呢?看下面这个例子: public class Pass { public static void test(String str) { str = "World"; } public static void main(String[] args) { String string = "Hello"; System.out.println(string); test(string); System.out.println(string); } } 结果是: Hello Hello 第三个例子: public class Pass { public static void test(StringBuffer str) { str.append("World"); } public static void main(String[] args) { StringBuffer string = new StringBuffer("Hello"); System.out.println(string); test(string); System.out.println(string); } } 结果: Hello HelloWorld 这我就不太明白了,既然String不是简单类型,那么它应该和对象是一样通过引用来传递的,可是结果却相反.而StringBuffer却是通过引用来传递的?
浏览: 326493 次
来自: 杭州
下说法有误!如果两个对象的hashCode值相同,我们应该认为 ...
11 1111 ...
Cloudera Hadoop5&Hadoop高阶管理 ...
感谢楼主~~~~长知识了
非常感谢楼主的分享,解决了我的问题
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
论坛徽章:0
经典的问题,但却不容易弄懂,尤其对有c基础的java程序员来说,更容易引起混乱,这里我试图简单点描述。
“java函数是传值的,java函数传递的参数是对象的引用”
这两句话好像初听上去有些矛盾,但却是事实,因而引起很多初学者的混乱。在这里我试图据个简单的例子来说明java的这个特性,可能不全面,希望大家来补全。
public class TestRef {
& & & &
& & & & public static void main(String[] args)
& & & & {
& & & & & & & & ValueObject vo1 = new ValueObject(&A&, 1);
& & & & & & & & System.out.println(&after vo1: & + vo1.getName()); //=A
& & & & & & & &
& & & & & & & & changeValue1(vo1);
& & & & & & & & System.out.println(&after changeValue1: & + vo1.getName());
& && && && && & //=A1, changed
& & & & & & & &
& & & & & & & & changeValue2(vo1);
& & & & & & & & System.out.println(&after changeValue2: & + vo1.getName());
& && && && && & //=A1, changeValue2内部的赋值不会影响这里。
& & & & }
& & & & /**
& & & &&&* 使用vo1自身的函数对其内部数据进行改变是有效的,函数外可反映出来
& & & &&&* 这种object称为可变的(mutable)
& & & &&&* @param vo1
& & & &&&*/
& & & & private static void changeValue1(ValueObject vo1) {
& & & & & & & & vo1.setName(&A1&);
& & & & }
& & & & /**
& & & &&&* 在函数内给vo1重新赋值不会改变函数外的原始值
& & & &&&* @param vo1
& & & &&&*/
& & & & private static void changeValue2(ValueObject vo1) {
& & & & & & & & vo1 = new ValueObject(&B&, 2);
& & & & & & & & System.out.println(&inside changeValue2: &+ vo1.getName());
& && && && && & //=B,赋值操作引起的结果变化仅在changeValue2内部有效
& & & & }
}
class ValueObject {
& & & &
& & & & public ValueObject() {}
& & & &
& & & & public ValueObject(String name, int id)
& & & & {
& & & & & & & & this.name =
& & & & & & & & this.id =
& & & & }
& & & &
& & & & private S
& & & &
& & & & public int getId() {
& & & & & & & &
& & & & }
& & & & public void setId(int id) {
& & & & & & & & this.id =
& & & & }
& & & & public String getName() {
& & & & & & & &
& & & & }
& & & & public void setName(String name) {
& & & & & & & & this.name =
& & & & }
}
复制代码
解释,vo1作为一个object,当它被用作函数参数的时候传递给函数的是一个引用值,这个名称有点怪,又有引用又有值,到底是引用还是值呢,就看你怎么理解了。如果你是去考试,官方的答案是值。可是看起来又象引用啊,希望从这个例子,你能理解java参数传递和和C/C++程序中的引用传递的不同的地方。另外,这也是java作为OO语言的特性之一:封装的体现。
先讲一下对象赋值的关系,举例来说,下列代码:
ValueObject v2, v3;
v2 = new ValueObject(&C&, 3); 粗体的部分创建了一个数据结构,假设存放在内存地址A000,赋值给句柄 v2
v3 = new ValueObject(&D&, 4); 粗体的部分创建了一个数据结构,假设存放在内存地址B000,赋值给句柄 v3
v2 = v3; 这句话的作用是把操作B000的地址的句柄的值付给了v2的句柄,使得v2和v3一样操作B000的地址,这意味着:
1.原来v2指向的地址A000变成无主的内存地址,将自动被jvm回收。
2.既然v2和v3指向同一片地址,对v3的修改v2也能得到,反之亦然。
整理得下列代码,请感兴趣的朋友运行验证
ValueObject v2 = new ValueObject(&C&, 3);
ValueObject v3 = new ValueObject(&D&, 4);
System.out.println(&after v2=v3&);
System.out.println(&v2= &+ v2.getName());//=D
System.out.println(&v3= &+ v3.getName());//=D
v3.setName(&C1&);
System.out.println(&after v3 setnameTo C1&);
System.out.println(&vo2= &+ v2.getName());//=C1
System.out.println(&vo3= &+ v3.getName());//=C1
因此,可以得出结论,java中对象的每个实例(instance, 比如vo1, v2, v3 都是ValueObject的实例)的内存地址是唯一的,它一旦被创建,能够对这个地址进行操作的就是每个实例自己,如果ValueObject类中没有public void setName之类的方法对这个类的实例中的数据进行修改的话,程序是没有任何别的方法可以修改ValueObject类的实例中的数据,这个就是java的封装特性。对于不提供修改内部数据的方法的类,我们称为不可变(immutable)的类。在函数中对传入的参数变量进行赋值操作,只能在函数范围内改变局部变量指向的引用地址,但是不会改变原始地址的内容。因此,在changeValue2(...)函数内部的vo1和函数外的vo1虽然名字相同,但是实际上是不同的实例变量,只不过指向了和函数外的vo1同样的地址,所以当我们用vo1=... 对其进行赋值的时候,只不过是把函数内的临时变量指向了新的地址,并没有改变原始vo1内存地址中的内容。这就是在运行changeValue2(...)之后,vo1的值在main范围内仍然没有被修改的原因。而changeValue1里面是调用的ValueObject本身的function来更改其内容,因此是原始内存地址中的数据被更改了,所以是全局有效的。
[ 本帖最后由 perryhg 于
00:50 编辑 ]
论坛徽章:0
原帖由 perryhg 于
20:03 发表
经典的问题,但却不容易弄懂,尤其对有c基础的java程序员来说,更容易引起混乱,这里我试图简单点描述。
“java函数是传值的,java传递的参数是对象的引用”
这两句话好像初听上去有些矛盾,但却是事实,因 ...
说的好~版猪辛苦:em11:
稍有积蓄, 积分 229, 距离下一级还需 271 积分
论坛徽章:0
原帖由 perryhg 于
19:03 发表
经典的问题,但却不容易弄懂,尤其对有c基础的java程序员来说,更容易引起混乱
不会吧,用了好几年C了,而且也写过C编译器,感觉应该算是有C基础了。
但我觉得更容易理解java中这种参数传递的本质啊。
所有的地方都是传值,无它。而且这也不会引起混乱。
白手起家, 积分 18, 距离下一级还需 182 积分
论坛徽章:0
实际上可以这样理解,java的函数还是传值的。
changeValue1(vo1)的调用,实际上是把main里面的vo1变量(句柄)的值(该值实际上又是vo1代表的对象的指针)传递给changeValue函数的局部变量。
传值是针对变量的,不能混淆变量本身和变量的值所代表的是引用还是值。
丰衣足食, 积分 915, 距离下一级还需 85 积分
论坛徽章:0
我也说:传值还是引用
只知道理解是否正确,请大家指教阿!
看了 《practical java》今天把这个问题搞清楚了,在这里备忘一下!
大家都认为java的引参是by reference来传递的,这个看法是错误的。引参是其实是通过by value来传递的。产生这个错误的原因很简单,因为java的对象的引用都是通过by referencr的。下面举例说明一下。
import java.awt.P
class PassByValue{
public static&&void modifyValue(Point pt,int j) {//pt,j为引参
pt.setLocaltion(5,5);& && & //& && &1
System.out.println(&During modifyPoint& + &pt=&+pt+&and j = &+j);
public static void main(String [] args){
Point p = new Point();& &&&//& && &&&2
int i = 10;
System.out.println(Before modifyPoint& + &pt=&+pt+&and j = &+j);
modifyValue(p , i );& && && & //& && && &3
System.out.println(After modifyPoint& + &pt=&+pt+&and j = &+j);
上面的这个例子在2处,生成了一个Point的对象,并将其赋值给一个对象的引用 变量 p。生成了一个int i=10。在3这个地方,通过调用modifyValue(),传入引参,p和i。对第一个参数pt调用setLocation(5,5)这个方法,然后把第二个参数 j 赋值为15。modifyValue()返回后,打印最后的结果。
& &Before modifyPoint p=java.awt.Point[x=0,y=0] and i=10;
& &During modifyPoint p=java.awt.Point[x=5,y=5] and i=15;
& &After& &modifyPoint p=java.awt.Point[x=5,y=5] and i=10;
从结果中大家可以看到,modifyPoint()修改了//2 里面建立的对象Point,却没有改变i的值。在main中,i 被赋值为10,用于引参是 通过by value 来传递的,所以modifyPoint()收到的是一个i的副本,然后将这个副本改成15,并返回。main里面的i并没有受到影响。
对比之下,你可能也认为//2中建立的Point对象也没有被modifyPoint()修改。毕竟java是通过by value来传递引参的。于是乎,在调用modifyPoint()并传入//2中建立的Point对象的时候,会像上面一样产生一个point对象的“复制品”来配合modifyPoint()的工作。因此在modifyPoint()里面对Point对象的复制品的修改是不会影响到main后面的,应为Point的对象和Point对象在modifyValue里面不是同一个对象嘛! 对不对呢? 答案是 错!!!!
& & 事实上modifyPoint是在和Point的对象的reference的复制品(引用复制品)打交道,而不是和Point的对象打交道。注意了p仅仅是一个引用而已,并且java是以by value的方式来传递引参的。更准确的说,java是通过by value来传递对象的引用的。当p从mian()里面传到modifyValue()的时候传递的是一个p(注意:p只是引用而已一个)的复制品pt,所以modifyPoint()是在和同一个对象打交道,因为pt,是p的一个copy,但是pt和p有相同的一个地址,这个地址指向的是同一个Point对象。所以,对pt的操作会改动Point的对象,也就出现了第三个结果
白手起家, 积分 18, 距离下一级还需 182 积分
论坛徽章:0
应当这样来思考
//其实你这个问题很简单,你和程序应当这样写。里边好多错误你难道没有看也来吗?
//关于JAVA里的传值还是传引用其实是一个很简单的问题。
//任何一个方法的传进去的参数都分为两种情况,一是传进去一个对象的形式,二是传进去是基本数据
//的形式。如果方法参数传进去的是对象比如public void function(Object one)那这个one 就是把一个one的
//引用传进去了,也就是我们以前讲的reference.他就是一根拉着对象的风筝线,不可断的。如果是第二
//种情况public void function(int one)那传进去的就是一个单单的一个基本数据了,你对这个数据的任何变化不会对原来那个基本数据
//有什么改动。
//就象你在程序里写这样一段
// int i = 0;
// int j =
// i 是不会变成5的。
//而如果换了对象
// Point p = new Point();
// Point pt =
// p 和pt 就会指向了同一个Point();他们二者都是那根绳子,一有变化就风筝就会动了,
// ====================================================================
import java.awt.P
public class PassByValue{
& & & & public static&&void modifyValue(Point pt,int j)
& & & & {//pt,j为引参
& & & & & & & & pt.setLocation(5,5);& && & //& && &1
& & & & & & & & j=15;
& & & & & & & & System.out.println(&During modifyPoint& + &pt=&+pt+&and j = &+j);
& & & & public static void main(String [] args)
& & & & & & & & Point p = new Point();& &&&//& && &&&2
& & & & & & & & int i = 10;
& & & & & & & & System.out.println(&Before modifyPoint& + &pt=&+p+&and j = &+i);
& & & & & & & & modifyValue(p , i );& && && & //& && && &3
& & & & & & & & System.out.println(&After modifyPoint& + &pt=&+p+&and j = &+i);
论坛徽章:0
//就象你在程序里写这样一段
// int i = 0;
// int j =
// i 是不会变成5的。
//而如果换了对象
// Point p = new Point();
// Point pt =
// p 和pt 就会指向了同一个Point();他们二者都是那根绳子,一有变化就风筝就会动了,
好多地方都举这个例子,但是我觉得这个例子不好,我当初还以为是原始数据类型int和对象类型Object的区别呢,后来才了解这是mutable和 immutable的区别,才写了个不同的例子
[ 本帖最后由 perryhg 于
14:33 编辑 ]
丰衣足食, 积分 806, 距离下一级还需 194 积分
论坛徽章:0
值传递还是引用传递,我就这样理解了
呵呵,看过两本书,写的也不一样,但是对此产生的结果都能认识到,看来大家理解的方式是不一样的。
perryhg说尤其对有c基础的java程序员来说,更容易引起混乱,我猜是漏了一个字,应该是没有C基础的吧。
原帖由 hncdyjh 于
22:36 发表
传值是针对变量的,不能混淆变量本身和变量的值所代表的是引用还是值。
kakasi (卡卡西せんせい)在以前说的好:
1.java参数传递值的。
2.java所有对像变量都是对像的引用。
这两个说法我认为很是经典。
我是这么理解的:
变量、变量的值和引用的概念在有些情况下有些可以互相替代,但却有完会不同的意义,很难让人搞清楚。
如多C书上都有如下这样的图,不知道这样理解好不好?
比如有两个变量
byte& & a=16;
String str=&he&;
第一列是内存地址,第二列是内存的内容,第三列是对应的变量。
0000:16 - a
0001:3&&- str
0002:
0003:h
0004:e
0005:k
0006:k
不知道地址可不可以这样编,字符串对像也不可能是这样存储,应该能说明意思吧,
也不知道java是不是这样的的意思,我是这样理解的。
复制代码
可以看出,a是一般变量,它的值就是16,
str是对像变量,它的值是“he&对像的地址3,所是说它是对像的引用。
当做参数传递时,都是传的它们的拷贝,也就是传值,改变它们的值不影响原来值。
(1)str2=str2=&kkk& ;//str2值为3;然后赋值为kk的地址。strt2的值改变了不影响str
(2)str2=str2.replace('h','k');str2值为3;改变了引用的值。但只是改变了str2和str共同的引用的对像的值。
=(等号)操作的是变量的值。
.(句点)操作的是引用的值。
我想这样认为.操作符就应该清楚对像改变了而不是因为参数是引用传递的吧
[ 本帖最后由 只爱一点点 于
13:21 编辑 ]
论坛徽章:0
师傅领进门,修行在个人;
静下心来冥思一下,相信很快就会豁然开朗,大彻大悟
支持总结,支持引用:em11:~~~
家境小康, 积分 1660, 距离下一级还需 340 积分
论坛徽章:0
关于传参的问题只要把栈和堆搞明白了就应该很容易理解了
java传参都是传值,也就是把栈里面的值复制一份传给参数
当然如果是原始类型就是栈内原始类型值复制了一份传递
如果是对象或者数组这样的引用类型,那么栈里面的值就是该对象的引用的值具体说就是地址了,把这个值复制一份传给方法,也就是复制了一个引用给方法去使用。
public void func1(int a){}
那么int i = 10;
func1(i);的时候,实际上是作了a=i的操作
public void fun2(Object o){}
那么Object m = new Object();
func2(m);的时候,也其实是作了o=m的操作
这样就比较容易理解了吧
北京盛拓优讯信息技术有限公司. 版权所有 京ICP备号 北京市公安局海淀分局网监中心备案编号:22
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处

我要回帖

更多关于 java传值和引用 的文章

 

随机推荐