6 回答
TA贡献1877条经验 获得超1个赞
Java始终是按值传递的。不幸的是,当我们传递一个对象的值时,我们将引用传递给它。这对初学者来说很困惑。
它是这样的:
public static void main(String[] args) { Dog aDog = new Dog("Max"); Dog oldDog = aDog; // we pass the object to foo foo(aDog); // aDog variable is still pointing to the "Max" dog when foo(...) returns aDog.getName().equals("Max"); // true aDog.getName().equals("Fifi"); // false aDog == oldDog; // true}public static void foo(Dog d) { d.getName().equals("Max"); // true // change d inside of foo() to point to a new Dog instance "Fifi" d = new Dog("Fifi"); d.getName().equals("Fifi"); // true}
在上面的例子中aDog.getName()
仍将返回"Max"
。值aDog
内main
未在功能改变foo
与Dog
"Fifi"
作为对象基准由值来传递。如果它是通过引用传递的,则aDog.getName()
in main
将"Fifi"
在调用之后返回foo
。
同样:
public static void main(String[] args) { Dog aDog = new Dog("Max"); Dog oldDog = aDog; foo(aDog); // when foo(...) returns, the name of the dog has been changed to "Fifi" aDog.getName().equals("Fifi"); // true // but it is still the same dog: aDog == oldDog; // true}public static void foo(Dog d) { d.getName().equals("Max"); // true // this changes the name of d to be "Fifi" d.setName("Fifi");}
在上面的例子中,Fifi
是调用后的狗的名字,foo(aDog)
因为对象的名字是在里面设置的foo(...)
。任何操作foo
执行上d
是这样的,对于所有的实际目的,它们被执行的aDog
,但它是不是可以改变变量的值aDog
本身。
TA贡献2041条经验 获得超4个赞
我刚刚注意到你引用了我的文章。
Java规范说Java中的所有内容都是按值传递的。在Java中没有“pass-by-reference”这样的东西。
理解这一点的关键是类似的东西
Dog myDog;
是不是狗; 它实际上是指向狗的指针。
这意味着,就在你拥有的时候
Dog myDog = new Dog("Rover");foo(myDog);
你实际上是将创建的对象的地址传递Dog
给foo
方法。
(我说的主要是因为Java指针不是直接地址,但最容易想到它们)
假设Dog
对象驻留在内存地址42处。这意味着我们将42传递给该方法。
如果方法被定义为
public void foo(Dog someDog) { someDog.setName("Max"); // AAA someDog = new Dog("Fifi"); // BBB someDog.setName("Rowlf"); // CCC}
让我们来看看发生了什么。
参数
someDog
设置为值42在线“AAA”
someDog
跟随Dog
它指向(Dog
地址42处的对象)要求
Dog
(地址为42的那个)将他的名字改为Max在线“BBB”
Dog
创建了一个新的。让我们说他在地址74我们将参数分配
someDog
给74在线“CCC”
someDog跟随
Dog
它指向(Dog
地址74处的对象)要求
Dog
(地址为74的那个)将他的名字改为Rowlf然后,我们回来了
现在让我们考虑一下方法之外会发生什么:
没有myDog
改变?
关键是。
记住这myDog
是一个指针,而不是一个实际的Dog
,答案是否定的。myDog
仍然有42的价值; 它仍然指向原始Dog
(但请注意,由于行“AAA”,它的名称现在是“Max” - 仍然是相同的狗;它myDog
的值没有改变。)
按照地址并改变最后的内容是完全有效的; 但是,这不会改变变量。
Java的工作方式与C完全相同。您可以分配指针,将指针传递给方法,按照方法中的指针操作并更改指向的数据。但是,您无法更改指针指向的位置。
在C ++,Ada,Pascal和其他支持pass-by-reference的语言中,您实际上可以更改传递的变量。
如果Java具有pass-by-reference语义,那么foo
我们在上面定义的方法会在BBB上myDog
分配的位置发生变化someDog
。
将引用参数视为传入的变量的别名。当分配该别名时,传入的变量也是如此。
TA贡献1963条经验 获得超6个赞
这将为您提供一些有关Java如何工作的见解,以至于在您下次讨论Java通过引用传递或通过值传递时,您只需微笑:-)
第一步请从脑海中删除以'p'“_ _ _ _ _ _ _”开头的单词,特别是如果您来自其他编程语言。Java和'p'不能写在同一本书,论坛,甚至txt中。
第二步记住,当你将一个Object传递给一个方法时,你传递的是Object引用,而不是Object本身。
学生:师父,这是否意味着Java是传递参考?
师父:蚱蜢,没有。
现在想想Object的引用/变量是什么/是什么:
变量保存位,告诉JVM如何到达内存中引用的Object(Heap)。
将参数传递给方法时,您不会传递引用变量,而是传递引用变量中的位副本。像这样:3bad086a。3bad086a代表了一种获取传递对象的方法。
所以你只是传递3bad086a,它是参考的价值。
您传递的是引用的值而不是引用本身(而不是对象)。
该值实际上是COPIED并赋予方法。
在下面(请不要尝试编译/执行此...):
1. Person person;2. person = new Person("Tom");3. changeName(person);4.5. //I didn't use Person person below as an argument to be nice6. static void changeName(Person anotherReferenceToTheSamePersonObject) {7. anotherReferenceToTheSamePersonObject.setName("Jerry");8. }
怎么了?
变量person在第1行中创建,并且在开头时为null。
在第2行创建一个新的Person对象,存储在内存中,并为变量person提供对Person对象的引用。那就是它的地址。比方说3bad086a。
保存Object的地址的变量person被传递给第3行中的函数。
在第4行,你可以听到沉默的声音
检查第5行的评论
创建一个方法局部变量 - anotherReferenceToTheSamePersonObject - 然后在#6行中产生魔力:
变量/引用人被逐位复制并传递给函数内的anotherReferenceToTheSamePersonObject。
没有创建Person的新实例。
“ person ”和“ anotherReferenceToTheSamePersonObject ”都保持相同的3bad086a值。
不要试试这个,但是人== anotherReferenceToTheSamePersonObject会是真的。
两个变量都具有引用的IDENTICAL COPIES,它们都引用相同的Person对象,堆上的SAME对象而不是COPY。
请注意,anotherReferenceToTheSamePersonObject箭头指向Object而不是指向变量person!
如果你没有得到它,那么只要相信我,并记住最好说Java是通过值传递的。那么,通过参考值传递。哦,更好的是传递变量值的副本!;)
现在可以随意讨厌我,但请注意,在讨论方法参数时,传递原始数据类型和对象之间没有区别。
你总是传递一份参考值的副本!
如果它是原始数据类型,则这些位将包含原始数据类型本身的值。
如果它是一个Object,那么这些位将包含告诉JVM如何到达Object的地址值。
Java是按值传递的,因为在方法中你可以根据需要修改引用的Object,但无论你多么努力,你都永远无法修改将继续引用的传递变量(不是p _ _ _ _ _ _ _)同样的对象无论如何!
上面的changeName函数永远不能修改传递的引用的实际内容(位值)。换句话说,changeName不能使Person人引用另一个Object。
当然,你可以缩短它,只是说 Java是值得传递的!
TA贡献1830条经验 获得超9个赞
Java的始终是按值传递,没有例外,永远。
那么如何让任何人都对此感到困惑,并相信Java是通过引用传递的,或者认为他们有一个Java作为参考传递的例子?关键是Java 在任何情况下都不会直接访问对象本身的值。对对象的唯一访问是通过对该对象的引用。因为Java对象总是通过引用访问,而不是直接访问,所以通常将字段和变量以及方法参数作为对象进行讨论,而当它们只是对对象的引用时。这种混淆源于这种(严格来说,不正确的)命名法的变化。
所以,在调用方法时
对于原始参数(
int
,long
等),pass by value是基元的实际值(例如,3)。对于对象,pass by value是对象引用的值。
所以,如果你有doSomething(foo)
和public void doSomething(Foo foo) { .. }
两个FOOS已复制引用指向同一个对象。
当然,通过值传递对对象的引用看起来非常像(并且在实践中无法区分)通过引用传递对象。
TA贡献1811条经验 获得超6个赞
在C ++中:注意:错误的代码 - 内存泄漏! 但它证明了这一点。
void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef){ val = 7; // Modifies the copy ref = 7; // Modifies the original variable obj.SetName("obj"); // Modifies the copy of Dog passed objRef.SetName("objRef"); // Modifies the original Dog passed objPtr->SetName("objPtr"); // Modifies the original Dog pointed to // by the copy of the pointer passed. objPtr = new Dog("newObjPtr"); // Modifies the copy of the pointer, // leaving the original object alone. objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to // by the original pointer passed. objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed}int main(){ int a = 0; int b = 0; Dog d0 = Dog("d0"); Dog d1 = Dog("d1"); Dog *d2 = new Dog("d2"); Dog *d3 = new Dog("d3"); cppMethod(a, b, d0, d1, d2, d3); // a is still set to 0 // b is now set to 7 // d0 still have name "d0" // d1 now has name "objRef" // d2 now has name "objPtr" // d3 now has name "newObjPtrRef"}
在Java中
public static void javaMethod(int val, Dog objPtr){ val = 7; // Modifies the copy objPtr.SetName("objPtr") // Modifies the original Dog pointed to // by the copy of the pointer passed. objPtr = new Dog("newObjPtr"); // Modifies the copy of the pointer, // leaving the original object alone.}public static void main(){ int a = 0; Dog d0 = new Dog("d0"); javaMethod(a, d0); // a is still set to 0 // d0 now has name "objPtr"}
Java只有两种类型的传递:内置类型的值,以及对象类型的指针值。
TA贡献2065条经验 获得超14个赞
基本上,重新分配Object参数不会影响参数,例如,
private void foo(Object bar) { bar = null;}public static void main(String[] args) { String baz = "Hah!"; foo(baz); System.out.println(baz);}
将打印出"Hah!"
而不是null
。这个工作的原因是因为bar
是一个值的副本baz
,它只是一个引用"Hah!"
。如果它本身就是实际参考,那么foo
将重新定义baz
为null
。
添加回答
举报