我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
当前回答
Java 始终是 pass-by-value,参数是经过的变量的副本,所有对象都是用参考来定义的,参考是存储一个记忆地址的变量,其中对象在记忆中。
查看评论以了解执行中发生了什么;跟随数字,因为它们显示执行的流动。
class Example
{
public static void test (Cat ref)
{
// 3 - <ref> is a copy of the reference <a>
// both currently reference Grumpy
System.out.println(ref.getName());
// 4 - now <ref> references a new <Cat> object named "Nyan"
ref = new Cat("Nyan");
// 5 - this should print "Nyan"
System.out.println( ref.getName() );
}
public static void main (String [] args)
{
// 1 - a is a <Cat> reference that references a Cat object in memory with name "Grumpy"
Cat a = new Cat("Grumpy");
// 2 - call to function test which takes a <Cat> reference
test (a);
// 6 - function call ends, and <ref> life-time ends
// "Nyan" object has no references and the Garbage
// Collector will remove it from memory when invoked
// 7 - this should print "Grumpy"
System.out.println(a.getName());
}
}
其他回答
public void foo(Object param)
{
// some code in foo...
}
public void bar()
{
Object obj = new Object();
foo(obj);
}
它是相同的......
public void bar()
{
Object obj = new Object();
Object param = obj;
// some code in foo...
}
不要考虑在这个讨论中不相关的站点。
你会遇到的最常见的运营商之一是简单的任务运营商“="......它将其右上的值归分为其左上的运营商: int cadence = 0; int speed = 0; int gear = 1; 这个运营商也可以用于对象归分对象参考。
很明显,这个运营商如何以两种不同的方式行动:分配值和分配参考;最后,当它是一个对象......第一,当它不是一个对象,即当它是一个原始的。
真相在代码中,让我们尝试一下:
public class AssignmentEvaluation
{
static public class MyInteger
{
public int value = 0;
}
static public void main(String[] args)
{
System.out.println("Assignment operator evaluation using two MyInteger objects named height and width\n");
MyInteger height = new MyInteger();
MyInteger width = new MyInteger();
System.out.println("[1] Assign distinct integers to height and width values");
height.value = 9;
width.value = 1;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are different things! \n");
System.out.println("[2] Assign to height's value the width's value");
height.value = width.value;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");
System.out.println("[3] Assign to height's value an integer other than width's value");
height.value = 9;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are different things yet! \n");
System.out.println("[4] Assign to height the width object");
height = width;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");
System.out.println("[5] Assign to height's value an integer other than width's value");
height.value = 9;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are the same thing now! \n");
System.out.println("[6] Assign to height a new MyInteger and an integer other than width's value");
height = new MyInteger();
height.value = 1;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are different things again! \n");
}
}
这就是我跑步的结果:
Assignment operator evaluation using two MyInteger objects named height and width [1] Assign distinct integers to height and width values -> height is 9 and width is 1, we are different things! [2] Assign to height's value the width's value -> height is 1 and width is 1, are we the same thing now? [3] Assign to height's value an integer other than width's value -> height is 9 and width is 1, we are different things yet! [4] Assign to height the width object -> height is 1 and width is 1, are we the same thing now? [5] Assign to height's value an integer other than width's value -> height is 9 and width is 9, we are the same thing now! [6] Assign to height a new MyInteger and an integer other than width's value -> height is 1 and width is 9, we are different things again!
我们不能那么确定,因为在 [6] 对象是相同的,然后我们将一个新的对象归分给其中一个,然后,对象有不同的价值! 他们现在如何区分,如果他们是相同的? 他们应该在这里也是相同的!!!
此操作员也可以用于对象分配对象参考。
在我所知道的范围内,Java只知道值的呼叫,这意味着对于原始数据类型,您将使用复印件工作,对于对象,您将使用对象的参考复印件工作。
public static void swap(StringBuffer s1, StringBuffer s2) {
StringBuffer temp = s1;
s1 = s2;
s2 = temp;
}
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("Hello");
StringBuffer s2 = new StringBuffer("World");
swap(s1, s2);
System.out.println(s1);
System.out.println(s2);
}
这将人口Hello World而不是World Hello,因为在交换函数中,您使用复印件,这些复印件不会对主要的参考产生影响。
public static void appendWorld(StringBuffer s1) {
s1.append(" World");
}
public static void main(String[] args) {
StringBuffer s = new StringBuffer("Hello");
appendWorld(s);
System.out.println(s);
}
如果您将 StringBuffer 更改为 String,它只会产生 Hello 因为 String 是不可变的。
public static void appendWorld(String s){
s = s+" World";
}
public static void main(String[] args) {
String s = new String("Hello");
appendWorld(s);
System.out.println(s);
}
但是,你可以为 String 做一个插槽,这将使它能够与 Strings 一起使用:
class StringWrapper {
public String value;
public StringWrapper(String value) {
this.value = value;
}
}
public static void appendWorld(StringWrapper s){
s.value = s.value +" World";
}
public static void main(String[] args) {
StringWrapper s = new StringWrapper("Hello");
appendWorld(s);
System.out.println(s.value);
}
编辑:我认为这也是使用 StringBuffer 的理由,当涉及到“添加”两个线条时,因为你可以修改原始对象,你不能用像 String 这样的不可变的对象。
“pass-by-value”和“pass-by-reference”是指变量;“pass-by-value”是指变量的值转移到函数/方法;“pass-by-reference”是指该变量的参考转移到函数;“pass-by-reference”是指变量的值转移到函数;“pass-by-reference”是指变量的值转移到函数。
它如同这样:
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
}
同样:
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");
}
有关参考通行和值通行的更多信息,请参见以下答案: https://stackoverflow.com/a/430958/6005228. 这更详细地解释了两者背后的语法和历史,并解释了为什么Java和许多其他现代语言似乎在某些情况下都会做两件事。
事實的結論是,在「通過通過」的表達中,意思是完全不同於Java的常見意思。
但技术术语通过参考/值从编程语言理论是谈论一个参考到记忆细胞持有变量,这是一个完全不同的东西。
Java 总是通过价值,没有例外,永远。
因此,怎样才能让任何人完全困惑,相信Java是通过参考,或者认为他们有一个Java作为通过参考的例子?关键点是Java从来没有提供直接访问对象本身的价值,在任何情况下。
因此,当呼叫一种方法时
对于原始论点(int、long等)而言,值的过渡是原始的实际价值(例如,3)。
所以,如果你有DoSomething(foo)和公共空白DoSomething(Foo foo) {.. } 两个 Foos 有复制的参考,指向相同的对象。
当然,通过值对一个对象的参考看起来非常相似(并且在实践中不可分辨的)通过对象的参考。