已经阅读了关于此主题的大量堆栈溢出答案,并且我已阅读了许多博客。我可以肯定地得出结论,Java是按值传递的。
但为了说服人们,我需要一些通过参考的语言证明。
所以有人可以提供一个通过引用传递的语言的实例,我们可以通过引用来解释java没有通过引用传递。
答案 0 :(得分:4)
所以有人可以给出一个通过引用传递的语言的实例,我们可以通过引用来解释java没有通过引用传递
Pass-by-ref与pass-by-value的最佳示例是swap。
void swap(String a, String b) {
String c = b;
b = a;
a = c;
}
void main() {
String a = "A";
String b = "B";
swap(a, b);
System.out.println(a); // A
System.out.println(b); // B
}
在这种情况下,当变量main.a指向与swap.a相同的对象时,您有两个对字符串的引用" A"。
vs C#(IDE One)支持by-ref。
void Swap(ref string a, ref string b) {
string c = b;
b = a;
a = c;
}
void main() {
string a = "A";
string b = "B";
Swap(ref a, ref b);
Console.WriteLine(a); // B
Console.WriteLine(b); // A
}
在这种情况下,变量main.a和swap.a是相同的引用,因此对swap.a的更改也发生在main.a。
那么这与
有何不同void swap(StringBuilder a, StringBuilder b) {
String a1 = a.toString();
String b1 = b.toString();
a.setLength(0);
a.append(b1);
b.setLength(0);
b.append(a1);
}
void main(){
StringBuilder a = new StringBuilder("A");
StringBuilder b = new StringBuilder("B");
swap(a, b);
System.out.println(a); // B
System.out.println(b); // A
}
在这种情况下,指向的对象会发生变化。例如:
public static void main(String... agv){
StringBuilder a = new StringBuilder("A");
StringBuilder b = new StringBuilder("B");
StringBuilder alsoA = a;
swap(a, b);
System.out.println(a); // B
System.out.println(b); // A
System.out.println(alsoA); //B
}
vs C#(IDEOne)
void Main() {
string a = "a";
string b = "b";
string alsoA = a;
Swap(ref a, ref b);
Console.WriteLine(a); // B
Console.WriteLine(b); // A
Console.WriteLine(alsoA); // A
}
如果您仍然不确定,Java Ranch会有good article。
答案 1 :(得分:3)
我不知道任何语言都是一直传递的,但C#有ref
修饰符,允许特定参数使用传递引用。这使您可以很容易地看到差异。例如:
using System;
public class Program
{
static void Main()
{
string x = "original x";
string y = "original y";
Modify(x, ref y);
Console.WriteLine(x);
Console.WriteLine(y);
}
static void Modify(string px, ref string py)
{
px = "modified x";
py = "modified y";
}
}
输出
original x
modified y
这是因为px
的分配不会影响调用代码中的x
:x
的值已传递给该方法。但是py
的分配确实更改了y
,因为y
是通过引用传递的; py
和y
基本上是同一存储位置的别名。
所有这些仅在您自己修改参数时才有意义。将上述程序与以下程序进行比较:
using System;
using System.Text;
public class Program
{
static void Main()
{
StringBuilder x = new StringBuilder("original x");
Modify(x);
Console.WriteLine(x);
}
static void Modify(StringBuilder px)
{
px.Length = 0;
px.Append("modified x");
}
}
现在Modify
方法根本不会更改px
的值 - 而是更改px
的值引用的对象。不需要按引用传递 - x
的值通过值传递给方法,并将其复制到px
。这就像在一张纸上复制你的家庭住址并将其交给某人。它不是复制房子本身 - 它只是模仿到达房子的方式。如果你给纸张的人去了,并把前门涂成红色,那么当你回家时,你会看到这种变化。
这就是理解variables, objects and references之间差异的重要原因。
答案 2 :(得分:0)
C ++有不同的传递参数的方法。一种方法是将指针类型指定为参数。我认为这与Java的作用很接近。指针按值传递。您可以修改指针引用的对象的状态,但不能更改调用函数引用的对象实例。
我包含了一个带有两个函数的C ++示例。一个函数按值调用,一个函数按引用语义调用。具有引用语义调用的函数可以更改调用函数引用的对象实例。
#include <iostream>
using namespace std;
class ClassA
{
public:
int a = 0;
};
void funcByValue(ClassA *param)
{
param->a = 1;
param = new ClassA();
}
void funcByReference(ClassA* ¶m)
{
param->a = 1;
param = new ClassA();
}
int main()
{
ClassA *objectA = new ClassA();
cout << objectA->a << "\n"; //1
cout << objectA << "\n"; //0000002B1D355AF0
//This call changes objectA's state
funcByValue(objectA);
cout << objectA->a << "\n"; //1
cout << objectA << "\n"; //0000002B1D355AF0
//This call changes the object objectA is referencing
funcByReference(objectA);
cout << objectA->a << "\n"; //0
cout << objectA << "\n"; //0000002B1D345610
}
答案 3 :(得分:0)