如果我将一个变量传递给一个函数但是将该变量标记为常量会自动通过引用传递吗?
void foo(const int a)
测试后:否,因为它打印不同的内存位置。
void foo(const int a)
{
cout << &a << endl;
}
int main()
{
int a = 5;
foo(a);
cout << &a << endl;
return 0;
}
不对吗?因为我只能将指针传递给内存位置,而不是真正通过引用。就像这里:Passing by reference in C
也许编译器可以发现final
应该指向相同的内存位置?
void foo(final int a)
与Java相同吗?
void foo(const int a)
我知道我在问题中包含了4种语言,但由于我使用这4种语言,我想知道很多。
有没有办法强制Java和C#来处理这个?我知道在C ++中我可以将&
添加到函数中,这正是我想要的。
void f(const int &a)
这就是我正在跳的Java和C#编译器在幕后做的事情。
答案 0 :(得分:4)
在Java中,所有变量都按值传递。
实际上复制了基元并且对象变量仍然是引用,这意味着对象变量的值实际上是引用 - &gt;您正在传递参考值。
尽管如此,你总是按值传递,与C ++相同,如果你没有明确地使用引用,你将通过值传递。
我几乎可以肯定它在C#中是一样的。
修改:我忘记了C
它在C中是相同的:默认情况下传递值。显然,你可以传递一个指针。在C ++中,这是扩展的,因此您可以将引用作为参数:
void function(int& intByReference) {
cout<<&intByReference<<endl; //prints x
}
int main() {
int n = 0;
cout<<&n<<endl; //prints x
function(n);
}
由于C ++包含类,因此有一个默认构造函数来复制对象:
class MyClass {
public:
MyClass(MyClass& objectToCopy) {
//copy your object here
//this will be called when you pass an instance of MyClass to a function
}
};
答案 1 :(得分:1)
你认为你的直觉可以指导你如何实现语言的细节,这是错误的。这根本不是真的。在C ++和C的情况下,规范很清楚地说明了应该如何处理它。
Java作为值语言传递可能在最终/常量/未触及值的规范中对此行为有一些规定。 (我不知道)但是只有规范可以允许这种行为。
答案 2 :(得分:0)
在回答你的问题之前,让我举一个例子来测试你的场景。
假设您通过传递变量void called(int a )
从方法void calledFrom()
调用方法int a
。
根据我的理解:
如果任何方法中a的值更改会影响另一个方法(calledFrom
中的a的变化会影响called
中a的值),那么其会引用,否则其按值调用。
现在让我们使用final
在java中测试它public class MyClass
{
int a;
public void setA(final int a)
{
this.a=a;
}
public void printA()
{
System.out.println(a);
}
}
从main方法执行此操作:
int a=10;
MyClass mclass=new MyClass();
mclass.setA(a);
mclass.printA();
a++;
mclass.printA();
输出是: 10 10
因此更改main
而不更改a
中MyClass
的值。所以对public void setA(final int a)
的调用并非按引用调用,而是按值调用。
键 final
可能会引起一些混乱。当您在方法签名中写入final时,不会以任何其他方式影响行为except you cant change the value of that parameter inside that method.
例如,如果你写
public void setA(final int a)
{
a++; //error
this.a=a;
}
您将收到编译错误
但你可以这样做
public void printA()
{
a++; //ok
System.out.println(a);
}
我认为这不仅仅是java所有其他语言都有相同的行为。你可以尝试其他语言。
要获得一个关于按值传递的明确概念,并在java的上下文中通过引用传递,您可以阅读this线程
或阅读this回答