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

什么是解释?


当前回答

在这里,每一个单一的答案都倾向于从其他语言中提到通过指标,并显示在Java中不可能做什么,因为任何原因,没有人试图从其他语言中展示如何实施通过对象的价值。

这个代码表明如何做这样的事情:

public class Test
{
    private static void needValue(SomeObject so) throws CloneNotSupportedException
    {
        SomeObject internalObject = so.clone();
        so=null;
        
        // now we can edit internalObject safely.
        internalObject.set(999);
    }
    public static void main(String[] args)
    {
        SomeObject o = new SomeObject(5);
        System.out.println(o);
        try
        {
            needValue(o);
        }
        catch(CloneNotSupportedException e)
        {
            System.out.println("Apparently we cannot clone this");
        }
        System.out.println(o);
    }
}

public class SomeObject implements Cloneable
{
    private int val;
    public SomeObject(int val)
    {
        this.val = val;
    }
    public void set(int val)
    {
        this.val = val;
    }
    public SomeObject clone()
    {
        return new SomeObject(val);
    }
    public String toString()
    {
        return Integer.toString(val);
    }
}

在这里,我们有一个函数需要值,它正在立即创建一个对象的克隆,需要在对象本身的类中实施,而该类必须被标记为克隆。

可能很好,Java没有通过参考语法,但称之为“通过价值”的语言沿着有愿望的思维线。

其他回答

我试图简化上面的例子,只保持问题的本质. 让我把这个作为一个容易记住和正确应用的故事。 故事如下: 你有一个宠物狗,吉米,尾巴长12英寸。

下次你旅行,你带狗,无意中,到一个邪恶的<unk>子,他也是长尾的仇恨者,所以他把它切到一个可怜的2英寸,但他这样做你的亲爱的吉米,而不是一个克隆。

public class Doggie {

    public static void main(String...args) {
        System.out.println("At the owner's home:");
        Dog d = new Dog(12);
        d.wag();
        goodVet(d);
        System.out.println("With the owner again:)");
        d.wag();
        badVet(d);
        System.out.println("With the owner again(:");
        d.wag();
    }

    public static void goodVet (Dog dog) {
        System.out.println("At the good vet:");
        dog.wag();
        dog = new Dog(12); // create a clone
        dog.cutTail(6);    // cut the clone's tail
        dog.wag();
    }

    public static void badVet (Dog dog) {
        System.out.println("At the bad vet:");
        dog.wag();
        dog.cutTail(2);   // cut the original dog's tail
        dog.wag();
    }    
}

class Dog {

    int tailLength;

    public Dog(int originalLength) {
        this.tailLength = originalLength;
    }

    public void cutTail (int newLength) {
        this.tailLength = newLength;
    }

    public void wag()  {
        System.out.println("Wagging my " +tailLength +" inch tail");
    }
}

Output:
At the owner's home:
Wagging my 12 inch tail
At the good vet:
Wagging my 12 inch tail
Wagging my 6 inch tail
With the owner again:)
Wagging my 12 inch tail
At the bad vet:
Wagging my 12 inch tail
Wagging my 2 inch tail
With the owner again(:
Wagging my 2 inch tail

我会以另一种方式说:

在 Java 引用中,这些引用是通过的(但不是对象),这些引用是通过的值(引用本身是复制的,你有 2 引用作为结果,你没有控制在方法中的第 1 引用下)。

例如,在Python相同的情况,但有文章,描述他们称之为Pass-by-reference,只有原因引用被使用。

我认为这个简单的解释可以帮助你理解,因为我想在我正在争论这一点时理解这一点。

当您将原始数据传输到函数呼叫时,其内容将复制到函数的论点,当您传输一个对象时,其参考将复制到函数的论点。

考虑到这个简单的例子,线条是Java的对象,当你改变一个线条的内容时,参考变量现在将指向一些新的参考,因为线条对象在Java中是不可变的。

String name="Mehrose";  // name referencing to 100

ChangeContenet(String name){
 name="Michael"; // refernce has changed to 1001

} 
System.out.print(name);  //displays Mehrose

很简单,因为正如我提到的那样,您不允许在呼叫函数中更改复制的参考,但问题在于当您通过 String/Object 序列时,该序列。

String names[]={"Mehrose","Michael"};

changeContent(String[] names){
  names[0]="Rose";
  names[1]="Janet"

}

System.out.println(Arrays.toString(names)); //displays [Rose,Janet]

你不能这样做

Student student1= new Student("Mehrose");

changeContent(Student Obj){
 obj= new Student("Michael") //invalid
 obj.setName("Michael")  //valid

}

有这么多长的答案,让我给你一个简单的答案:

Java 总是按值传达一切,也就是说,参考也按值传达。

简而言之,您无法改变任何参数的值,但您可以通过对象参考的方法或属性更改。

首先,我们应该明白什么是通过值或通过参考的意思。

通过值:方法参数值复制到另一个变量,然后复制的对象通过,这就是为什么它被称为通过值。

public class Balloon {

    private String color;

    public Balloon(){}

    public Balloon(String c){
        this.color=c;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

public class Test {

    public static void main(String[] args) {

        Balloon red = new Balloon("Red"); //memory reference 50
        Balloon blue = new Balloon("Blue"); //memory reference 100

        swap(red, blue);
        System.out.println("red color="+red.getColor());
        System.out.println("blue color="+blue.getColor());

        foo(blue);
        System.out.println("blue color="+blue.getColor());

    }

    private static void foo(Balloon balloon) { //baloon=100
        balloon.setColor("Red"); //baloon=100
        balloon = new Balloon("Green"); //baloon=200
        balloon.setColor("Blue"); //baloon = 200
    }

    //Generic swap method
    public static void swap(Object o1, Object o2){
        Object temp = o1;
        o1=o2;
        o2=temp;
    }
}

当我们执行上述程序时,我们会跟踪输出。

red color=Red
blue color=Blue
blue color=Red

Balloon red = new Balloon("Red");
Balloon blue = new Balloon("Blue");

public static void swap(Object o1, Object o2){ //o1=50, o2=100
    Object temp = o1; //temp=50, o1=50, o2=100
    o1=o2; //temp=50, o1=100, o2=100
    o2=temp; //temp=50, o1=100, o2=50
} //method terminated

如果你已经明白了这一点,你可以轻松地理解混乱的原因. 因为变量只是对物体的参考,我们会感到困惑,我们正在通过参考,所以Java通过参考。

现在,让我们分析 foo() 方法执行。

private static void foo(Balloon balloon) { //baloon=100
    balloon.setColor("Red"); //baloon=100
    balloon = new Balloon("Green"); //baloon=200
    balloon.setColor("Blue"); //baloon = 200
}

第一行是最重要的,当我们称之为一个方法时,该方法在参考位置上被称为对象,在这一点上,气球指向100,因此它的颜色变成红色。