我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
当前回答
有一个工作室在Java的参考,让我用这个例子解释:
public class Yo {
public static void foo(int x){
System.out.println(x); //out 2
x = x+2;
System.out.println(x); // out 4
}
public static void foo(int[] x){
System.out.println(x[0]); //1
x[0] = x[0]+2;
System.out.println(x[0]); //3
}
public static void main(String[] args) {
int t = 2;
foo(t);
System.out.println(t); // out 2 (t did not change in foo)
int[] tab = new int[]{1};
foo(tab);
System.out.println(tab[0]); // out 3 (tab[0] did change in foo)
}}
我希望这能帮助!
其他回答
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());
}
}
只需显示对比,请比较以下 C++ 和 Java 剪辑:
在 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 只有兩種通過: 根據內置類型的價值,並根據對象類型的指標的價值。
在我所知道的范围内,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 这样的不可变的对象。
Java 只通过值,这是一个很简单的例子来验证这一点。
public void test() {
MyClass obj = null;
init(obj);
//After calling init method, obj still points to null
//this is because obj is passed as value and not as reference.
}
private void init(MyClass objVar) {
objVar = new MyClass();
}
参考是常见的值,无论你使用哪种语言。
(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223] -> 47
(Foo)[47] -> 5
这就是跳板的工作方式。
在每个例子上创建了一个值 - 一个现有值的副本 - 现在是接收方法来处理它. 当你写“Foo”在方法,它是从EAX,或者自动右转,或双右转,过程取决于语言如何工作和 / 或什么类型的Foo独裁。
现在我们把Foo转到方法:
因此,简而言之,在Java本身的术语中,Java是通过价值,在那里价值可以是:无论是真实的价值还是参考的价值。