`

Java is Pass by Value | Java只有值传递

阅读更多
in C and JAVA, arguments are passed by value.

Java Language Spec中其实已经阐述过Java中都是值传递:
JLS8.4.1. Formal Parameters(形式参数) : http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.1
引用
When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables, each of the declared type, before execution of the body of the method or constructor. The Identifier that appears in the DeclaratorId may be used as a simple name in the body of the method or constructor to refer to the formal parameter.
当方法被调用时,会在方法执行前用实际参数的值创建并初始化一个新的参数变量,作为形式参数传给被调用方法。



概念:
值传递:
这个好理解,C/C++/Java等语言中体系下对pass by value的理解都是一致的:调用带参方法foo时,传递给方法形参的是实参的值的副本。所以,foo对传入的参数值的修改仅是对副本的修改,实参值不会因为foo对形参的修改而改变:
  	
void foo(int j) {
  j = 0;  /*  modifies the copy of the argument received by the function  */
}

int main(void) {
  int k=10;
  foo(k);
  /*  k still equals 10  */
}
	public static void main(String[] args) {
		int i = 10;
		foo(i);
		System.out.println(i); //i还是10
	}
	
	static void foo(int j) {
		j = 0;
	}

引用传递:
说引用传递前先说引用。reference的概念,在C语言中是没有,C++和Java中引入了reference的概念,但两种语言中reference的的概念是有本质区别的。
C++
引用
Src:http://www.cnblogs.com/kingln/archive/2008/03/29/1129118.html
C++中的引用就是个别名,对引用的任何操作就是对被引用物的操作。如下例子:
int m;
int &n = m;
n是m的一个引用(reference),m是被引用物(referent)。 n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。
C++中的引用遵从如下规则:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
C++引用示例程序
//k被初始化为i的引用。 
//语句k = j并不能将k修改成为j的引用,只是把k的值改变成为6。 
//由于k是i的引用,所以i的值也变成了6。 
int i = 5; 
int j = 6; 
int &k = i; 
k = j; // k和i的值都变成了6; 

Java中reference的概念就不分析了,就是指向堆中引用类型对象实例的栈中变量。总之,Java中的reference和C/C++的指针更像一些,和C++的reference很不一样。
通过对引用的分析,说说引用传递的概念:
C中没有引用传递这一说(值传递/地址传递(指针传递)),而所谓“引用传递”的提法,就是出自C++(出了个 & nickname 这样一个reference概念,而通过该种方式传参既区别于值传递,又区别于指针传递,完了就取了个名叫引用传递)。C++中的引用传递在swap()例子中可以得到典型的体现:
void swap(int &a,int &b)
{
     int temp;
     temp=a;
     a=b;
     b=temp;
     cout<<a<<’ ‘<<b<<’\n’;
}
int main(){
    int x=1;
    int y=2;
    swap(x,y);
    cout<<x<<’ ‘<<y<<’\n’;
    return 0;
}
输出为2,1;2,1。C++之引用只是别名,对作为形参的引用的任何操作就是对实参本身的操作。



Java中为什么有reference的概念,却没有引用传递那?(基本数据类型肯定是值传递,所以下面只谈引用数据类型作为参数传递的情况)
首先,假设Java存在引用传递。既然“引用传递”,肯定如C++一样,是传引用本身;这个引用传递的阐述肯定应该是:将方法外部的引用(变量)作为实参,直接传递给被调用方法的形参。因为方法内外持有的是同一个引用(变量),那么肯定会得出以下共识:
      1  方法内部对引用的重新赋值,会在方法外体现(内外都指向了一个新的对象);
      2  方法内部对引用所指向对象的属性的变更,会在方法外体现。
可是实际情况是:
方法内部对内部引用的重新赋值,并不会改变外部引用所指向的对象;
方法内部对内部引用所指向对象的属性的变更,改变了外部引用所指向对象的属性值。

假设中的共识1是与我们实际看到的结果相违背的!所以说,java中不存在引用传递。
混淆源自C++/Java中同样都叫reference;争执源自不去考虑两者“引用”概念的区别。



Java中引用数据类型作为参数传递的方式
如上面所引用JLS中的阐述所说,当传递引用(变量)时,使用引用的值(就是所指向的对象实例的地址)创建并初始化了一个新的引用变量,将该新的引用变量传给了被调用方法。从本质上来说,这就是值传递!




Java中的reference,更像是C/C++中的指针。但Java中引用数据类型作为参数传递的方式,是明显不同于指针传递的:Java中作为形参的引用(变量),其存放的内容是实参所指向对象实例的地址值;而C/C++中的指针传递,作为形参的指针,其存放的内容是实参的地址值。
但从本质上来说,他们都是传递地址值的值传递。
而C++中的引用,其“一旦创建必须初始化,一旦初始化就不能改变其引用关系”的特点,导致了对引用的操作无论何时都是对被引用物的操作(我们不去深究C++中的引用是否分配了内存,因为在C++程序员之间这都是一个没有定论的话题 ISO C++ 3.7 It is unspecified whether or not a reference requires storage),所以C++的引用传递,传递的就是实参本身。这也正是引用传递这个概念想要表达的东西:传的就是实参本身,被调用方法的任何操作,都是对实参本身的操作。
引用
C++ : Is there any way to find the address of a reference?
http://stackoverflow.com/questions/1950779/is-there-any-way-to-find-the-address-of-a-referenceReferences don't have their own addresses, although references may be implemented as pointers, there is no need or guarantee of this.





总之,java只有值传递:
当传递的是基本数据类型时,地球人都认同是值传递;
当传递的是引用数据类型时,传递的不是该引用(变量)本身(所以不是引用传递)!而是该引用变量的一个副本,而副本的产生遵从的就是值传递的原则(原引用变量中的所指向对象地址信息直接赋给该副本),所以归根结底还是值传递。






参考资料 Sources:
Does Java pass by reference or pass by value?
http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
Is “C” Pass by Value or Pass by Reference?
http://geeki.wordpress.com/2010/10/13/is-c-pass-by-value-or-pass-by-reference/
C++值传递、指针传递、引用传递的区别:
http://www.cnblogs.com/yjkai/archive/2011/04/17/2018647.html



Understanding Weak References:
http://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html
引用
引用从强到弱:
string > soft > weak > phantom
weakly-referenced objects will probably get collected by the JVM as soon as they become eligible for GC (and the WeakReference cleared). A weak reference to a would look like new WeakReference<Object>(a). Weak references are useful in the case that you want a cache whereby the data is only needed if the keys exist as strongly-reachable elsewhere (e.g. HttpSessions)
softly-referenced objects will probably hang around in the JVM until it absolutely needs to recover memory(如,内存不足时). Soft references are useful for caches where the values are long-lived but can collected if necessary.



Example:
Tips:面试时遇到该类问题,为了避免混淆,如果原题的实参和方法形参名字是一样的,可以改成不一样的再做,以免自己脑子混乱起来(如这里的例一实参为s,形参为str;例二实参为a,b,形参为x,y)
public class JavaIsPassByValue {
	public static void main(String[] args) {
		String s = "a";
		say(s);
		System.out.println(s);
	}
	static void say(String str) {
		str = str + "b";
	}
}
结果:a
说明:设字符串常量"a"分配在地址为0x0001的Method Area里、字符串常量"ab"分配在地址为0x0002的Method Area里。



public class TestStringBuffer {  
  
    public static void main(String[] args) {  
      
        StringBuffer a=new StringBuffer("A");  
        StringBuffer b=new StringBuffer("B");  
        method(a,b);  
        System.out.println(a+","+b);  
    }  
    public static void method(StringBuffer x,StringBuffer y){         
        x.append(y);   
        y=x;  
    }  
}  
结果:AB,B
说明:设存放有A的StringBuffer对象分配在地址为0x1的堆空间,存放有B的StringBuffer对象分配在地址为0x2的堆空间
  • 大小: 28.5 KB
  • 大小: 17.5 KB
分享到:
评论

相关推荐

    Java的按值传递和按引用传递分析.rar

    1. **按值传递(Pass by Value)** - Java中的基本类型(如int, double, char等)是按值传递的。这意味着当你将一个基本类型的变量作为参数传递给方法时,实际传递的是该变量的副本,而不是变量本身。在方法内部对...

    java参数的传递与返回值

    参数的传递方式主要有两种:值传递(Pass-by-value)和引用传递(Pass-by-reference)。Java主要采用值传递的方式。 ##### 1. 值传递 当我们将基本数据类型作为参数传递给方法时,实际上是传递了该数据的值的一个...

    C语言地址传递与值传递

    C语言中的函数调用机制包括值传递(value passing)和地址传递(address passing),通常被称为按值传递和按引用传递。C语言默认使用的是值传递机制,但是可以通过传递指针来实现类似地址传递的效果。下面将详细介绍这两...

    C++单向按值传递(产生临时对象) 双向按引用传递(不产生临时对象不占任何内存).rar

    本资料主要探讨了两种常见的参数传递方式:按值传递(pass by value)和按引用传递(pass by reference)。下面将详细阐述这两种方法的特点以及它们在实际编程中的应用。 一、按值传递(Pass By Value) 按值传递是...

    Java基础思考之数据传递Java系列2021.pdf

    在Java编程语言中,数据传递主要分为两种方式:按值传递(Pass by Value)和按引用传递(Pass by Reference)。这两种方式的理解对于深入理解Java对象和方法调用机制至关重要。 首先,我们要明确一点,Java中所有的...

    值传递与引用传递-内存解析

    在编程语言中,值传递和引用传递是函数参数传递的两种基本方式,它们涉及到内存管理、数据安全以及程序效率等多个重要方面。这篇文章将深入探讨这两种传递方式,并通过内存解析来帮助理解它们的工作原理。 首先,...

    java参数传递

    对于原始类型,Java采用“按值传递”(Pass by Value)的方式。这意味着当一个原始类型的变量作为参数传递给方法时,方法获得的是该变量的一个副本。任何在方法内部对该副本的修改都不会影响到原始变量的值。例如:...

    Java按值传递和按址传递(面试常见)

    Java编程语言中的参数传递主要有两种方式:按值传递(pass by value)和按引用传递(pass by reference),尽管Java官方并不支持真正的按引用传递,但其行为类似于按引用传递。这两种传递方式在面试和笔试中经常出现...

    java学习参数传递 杨辉三角,大学java作业题

    在Java中,函数参数的传递方式只有两种,即按值传递(Pass by Value)和按引用传递(Pass by Reference)。实际上,Java中所有的参数传递都是按值传递,这意味着当你将一个变量传递给方法时,方法接收到的是该变量的...

    三种参数传递

    •按值传递(pass by value) •地址传递(pass by pointer) •引用传递(pass by reference) 按值传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的...

    java源码包---java 源码 大量 实例

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM...

    浅谈Java中方法的参数传值.zip

    Java中,方法参数的传递主要有两种方式:值传递(Pass by Value)和引用传递(Pass by Reference)。不过,Java并没有真正的引用传递,而是通过对象引用来模拟引用传递的效果。下面我们详细讨论这两种方式。 2. 值...

    iBy0PASS.rar

    iBy0PASS.rar

    Java编程那些事儿55—方法重载和参数传递

    Java中的参数传递有两种主要的方式:值传递(Pass-by-value)和引用传递(Pass-by-reference)。虽然Java主要是基于值传递的,但在处理对象时,实际上传递的是指向对象的引用,因此在某些情况下也会被称为引用传递。...

    js-pass-by-value-vs-pass-by-reference-arrays:测试Java中数组的按值传递与按引用传递

    在Javascript中测试数组的按值传递与按引用传递。 解释 我最初查看Javascript是按值传递还是引用传递,发现除对象之外,它按值传递。 我创建了一个测试环境,该环境将创建一个大的整数数组并将该数组多次传递给函数...

    java英文笔试面试题.pdf

    5. **按值传递(Pass By Value)与按引用传递(Pass By Reference)**:按值传递是指传递变量的副本,而按引用传递则传递变量的地址,意味着对参数的改变会影响到原始变量。 6. **Map与HashMap**:`Map`是Java的一...

    《Java-面向对象程序设计基础》章:Java语法基础(与“方法”有关文档共49张).pptx

    * 在 Java 中进行赋值操作或函数调用中传递参数时,遵循值传递(Pass By Value)的原则,即传递的永远是参数的值。 * 关键字 this 代表方法的调用者,即本次调用了该方法的对象。 标识符 * 在 Java 语言中,标识符...

Global site tag (gtag.js) - Google Analytics