我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。

什么是解释?


当前回答

Java,当然,毫无疑问,是“通过价值”。 此外,由于Java是(主要)对象导向和对象与参考工作,它很容易被困惑,并认为它是“通过参考”

但要测试它是否真的通过值或通过参考,你可以使用原始类型和参考:

@Test
public void sampleTest(){
    int i = 5;
    incrementBy100(i);
    System.out.println("passed ==> "+ i);
    Integer j = new Integer(5);
    incrementBy100(j);
    System.out.println("passed ==> "+ j);
}
/**
 * @param i
 */
private void incrementBy100(int i) {
    i += 100;
    System.out.println("incremented = "+ i);
}

产量是:

incremented = 105
passed ==> 5
incremented = 105
passed ==> 5

因此,在两种情况下,任何在方法中发生的事情都不会改变真正的对象,因为对象的价值已经过去了,而不是对象本身的参考。

但是,当你将自定义对象转移到一种方法,而一种方法并改变它时,它也会改变真正的对象,因为即使你通过了对象,你也将其参考作为一种价值转移到一种方法。

@Test
public void sampleTest2(){
    Person person = new Person(24, "John");
    System.out.println(person);
    alterPerson(person);
    System.out.println(person);
}

/**
 * @param person
 */
private void alterPerson(Person person) {
    person.setAge(45);
    Person altered = person;
    altered.setName("Tom");
}

private static class Person{
    private int age;
    private String name; 

    public Person(int age, String name) {
        this.age=age;
        this.name =name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Person [age=");
        builder.append(age);
        builder.append(", name=");
        builder.append(name);
        builder.append("]");
        return builder.toString();
    }

}

在这种情况下,产量是:

Person [age=24, name=John]
Person [age=45, name=Tom]

其他回答

Java 严格要求 pass-by-value. 通过使用 pass-by-values 的参数不会影响/改变原始变量. 在下一个程序中,我们启动了一种称为 'x' 的变量,并使用 pass-by-value 技术来证明变量的值如何保持不变。

public class Main 
{    
   public static void main(String[] args)
   { 
       //Original value of 'x' will remain unchanged 
       // in case of call-by-value 
   
       int x = 5;
       System.out.println( "Value of x before call-by-value: " + x);
       // 5

       processData(x);
       System.out.println("Value of x after call-by-value: " + x);
       // 5
   }
   public static void processData(int x) 
   { 
       x=x+10;          
   }
}

通过值和通过参考值之间的差异

什么是 Pass by Value?

通过值,函数参数的值将复制到记忆中的另一个位置,在函数内访问或修改变量时,它只会访问复制。

通过参考,记忆地址转移到该函数,换句话说,函数可以访问实际变量。

定义

Pass by value 是指将函数参数值复制到另一个变量的机制,而 pass by reference 是指将实际参数转移到函数的机制。

变化

目前的参数

简单的计划

import java.io.*;
class Aclass
{
    public int a;
}
public class test
{
    public static void foo_obj(Aclass obj)
    {
        obj.a=5;
    }
    public static void foo_int(int a)
    {
        a=3;
    }
    public static void main(String args[])
    {
        //test passing an object
        Aclass ob = new Aclass();
        ob.a=0;
        foo_obj(ob);
        System.out.println(ob.a);//prints 5

        //test passing an integer
        int i=0;
        foo_int(i);
        System.out.println(i);//prints 0
    }
}

从 C/C++ 程序员的观点来看,Java 使用通过值,因此对于原始数据类型(int、char 等)的函数的变化不会反映在呼叫函数中,但是当您通过对象并在函数中更改其数据会员或呼叫会员函数可以改变对象的状态时,呼叫函数会得到变化。

一般来说,Java有原始类型(int、bool、char、double等)直接通过值,然后Java有对象(所有来自java.lang.Object的一切)。对象实际上总是通过参考处理(一个参考是指标,你不能触摸)。这意味着实际上,对象通过参考,因为参考通常并不有趣。

理解它在两个步骤:

您无法更改对象本身的参考,但您可以使用此已过的参数作为对象的参考。

如果您想要更改参考背后的值,您只会在同一名称“d”的字符串上宣布一个新的变量。

public static void foo(Dog d) {
  d.Name = "belly";
  System.out.println(d); //Reference: Dog@1540e19d

  d = new Dog("wuffwuff");
  System.out.println(d); //Dog@677327b6
}
public static void main(String[] args) throws Exception{
  Dog lisa = new Dog("Lisa");
  foo(lisa);
  System.out.println(lisa.Name); //belly
}

创建新点对象创建新点参考,并启动该参考到点(参考到)上以前创建的点对象. 从这里,通过点对象生活,您将通过pnt1参考访问该对象. 所以我们可以说,在Java中,您通过其参考操纵对象。

此分類上一篇

public static void tricky(Point arg1, Point arg2) {
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args) {
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X1: " + pnt1.x + " Y1:" + pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);  
}

该计划的流动:

Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);

System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
System.out.println(" ");

预计产量将是:

X1: 0     Y1: 0
X2: 0     Y2: 0

在此线上“pass-by-value”进入游戏中。

tricky(pnt1,pnt2);           public void tricky(Point arg1, Point arg2);

 arg1.x = 100;
 arg1.y = 100;

此分類上一篇

下一篇: 迷人的方法

Point temp = arg1;
arg1 = arg2;
arg2 = temp;

在这里,您首先创建一个新的 temp 点参考,将指向同一个位置,如 arg1 参考。 然后您将移动 arg1 参考,以指向同一个位置,如 arg2 参考。

从这里,迷人的方法的范围已经消失了,你不再有任何访问参考: arg1, arg2, temp. 但重要注意的是,当它们“在生活中”时,你所做的一切都会永久地影响它们所指向的对象。

X1: 0         Y1: 0
X2: 0         Y2: 0
X1: 100       Y1: 100
X2: 0         Y2: 0