如何在Java中为原语进行等效的传递

Stu*_*ent 111 java pass-by-reference

这个Java代码:

public class XYZ {   
    public static void main(){  
        int toyNumber = 5;   
        XYZ temp = new XYZ();  
        temp.play(toyNumber);  
        System.out.println("Toy number in main " + toyNumber);  
    }

    void play(int toyNumber){  
        System.out.println("Toy number in play " + toyNumber);   
        toyNumber++;  
        System.out.println("Toy number in play after increement " + toyNumber);   
    }   
}  
Run Code Online (Sandbox Code Playgroud)

将输出:

 
Toy number in play 5  
Toy number in play after increement 6  
Toy number in main 5  

在C++中,我可以通过toyNumber引用传递变量以避免阴影,即创建同一个变量的副本,如下所示:

void main(){  
    int toyNumber = 5;  
    play(toyNumber);  
    cout << "Toy number in main " << toyNumber << endl;  
}

void play(int &toyNumber){  
    cout << "Toy number in play " << toyNumber << endl;   
    toyNumber++;  
    cout << "Toy number in play after increement " << toyNumber << endl;   
} 
Run Code Online (Sandbox Code Playgroud)

并且C++输出将是这样的:

Toy number in play 5  
Toy number in play after increement 6  
Toy number in main 6  

我的问题是 - 考虑到Java是通过值传递而不是通过引用传递,Java中的等效代码与C++代码获得相同的输出什么?

las*_*owh 169

你有几个选择.最有意义的那个取决于你想要做什么.

选择1:使toyNumber成为类中的公共成员变量

class MyToy {
  public int toyNumber;
}
Run Code Online (Sandbox Code Playgroud)

然后将对MyToy的引用传递给您的方法.

void play(MyToy toy){  
    System.out.println("Toy number in play " + toy.toyNumber);   
    toy.toyNumber++;  
    System.out.println("Toy number in play after increement " + toy.toyNumber);   
}
Run Code Online (Sandbox Code Playgroud)

选择2:返回值而不是通过引用传递

int play(int toyNumber){  
    System.out.println("Toy number in play " + toyNumber);   
    toyNumber++;  
    System.out.println("Toy number in play after increement " + toyNumber);   
    return toyNumber
}
Run Code Online (Sandbox Code Playgroud)

这个选择需要对main中的callsite进行少量更改才能读取toyNumber = temp.play(toyNumber);.

选择3:使它成为一个类或静态变量

如果这两个函数是同一个类或类实例上的方法,则可以将toyNumber转换为类成员变量.

选择4:创建int类型的单个元素数组并传递它

这被认为是hack,但有时用于从内联类调用返回值.

void play(int [] toyNumber){  
    System.out.println("Toy number in play " + toyNumber[0]);   
    toyNumber[0]++;  
    System.out.println("Toy number in play after increement " + toyNumber[0]);   
}
Run Code Online (Sandbox Code Playgroud)

  • 清晰的解释,特别适合提供有关如何编码所需效果的多种选择.对我现在正在做的事情有直接的帮助!这个问题已经结束,这很坚定. (2认同)

Ker*_*ğan 29

Java不是通过引用调用它只是按值调用

但是对象类型的所有变量实际上都是指针.

因此,如果您使用Mutable对象,您将看到所需的行为

public class XYZ {

    public static void main(String[] arg) {
        StringBuilder toyNumber = new StringBuilder("5");
        play(toyNumber);
        System.out.println("Toy number in main " + toyNumber);
    }

    private static void play(StringBuilder toyNumber) {
        System.out.println("Toy number in play " + toyNumber);
        toyNumber.append(" + 1");
        System.out.println("Toy number in play after increement " + toyNumber);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出此代码:

run:
Toy number in play 5
Toy number in play after increement 5 + 1
Toy number in main 5 + 1
BUILD SUCCESSFUL (total time: 0 seconds)
Run Code Online (Sandbox Code Playgroud)

您也可以在标准库中看到此行为.例如Collections.sort(); Collections.shuffle(); 这些方法不返回新列表,而是修改它的参数对象.

    List<Integer> mutableList = new ArrayList<Integer>();

    mutableList.add(1);
    mutableList.add(2);
    mutableList.add(3);
    mutableList.add(4);
    mutableList.add(5);

    System.out.println(mutableList);

    Collections.shuffle(mutableList);

    System.out.println(mutableList);

    Collections.sort(mutableList);

    System.out.println(mutableList);
Run Code Online (Sandbox Code Playgroud)

输出此代码:

run:
[1, 2, 3, 4, 5]
[3, 4, 1, 5, 2]
[1, 2, 3, 4, 5]
BUILD SUCCESSFUL (total time: 0 seconds)
Run Code Online (Sandbox Code Playgroud)

  • 这不是问题的答案.它会回答这个问题,如果它建议创建一个包含单个元素的整数数组,然后在方法`play`中修改该元素; 例如`mutableList [0] = mutableList [0] + 1;`.正如欧内斯特弗里德曼希尔所说. (2认同)

Ing*_*ngo 18

做一个

class PassMeByRef { public int theValue; }
Run Code Online (Sandbox Code Playgroud)

然后将引用传递给它的实例.请注意,最好避免通过其参数改变状态的方法,尤其是在并行代码中.

  • @duffymo - 当然你可以随心所欲地投票 - 但你有没有考虑过OP的问题?他希望通过引用传递和int - 如果我通过值传递对上述实例的引用,这就完成了. (14认同)
  • @duffymo:嗯?你错了,或者误解了这个问题.这是**在Java中执行OP请求的传统方式之一. (7认同)
  • @duffymo:你的评论在很多层面都是错误的.SO是关于提供有用的答案和评论,你只是简单地选择正确的答案,因为(我猜)它不适合你的编程风格和哲学.你能否至少提供一个更好的解释,甚至是对原始问题的更好答案? (5认同)
  • 被我贬低.这在很多层面都是错误的.Java始终是值得传递的.没有例外. (3认同)
  • @duffymo就是我所说的:按值传递引用。您如何认为通过引用传递是通过减慢引用速度的语言完成的? (2认同)

Ern*_*ill 10

您不能通过Java中的引用传递基元.当然,对象类型的所有变量实际上都是指针,但我们将它们称为"引用",它们也总是按值传递.

在您确实需要按值传递基元的情况下,人们有时会做的是将参数声明为基本类型的数组,然后将单元素数组作为参数传递.所以你传递一个引用int [1],在方法中,你可以改变数组的内容.


小智 10

对于快速解决方案,您可以使用AtomicInteger或任何原子变量,这些变量将允许您使用内置方法更改方法内的值.这是示例代码:

import java.util.concurrent.atomic.AtomicInteger;


public class PrimitivePassByReferenceSample {

    /**
     * @param args
     */
    public static void main(String[] args) {

        AtomicInteger myNumber = new AtomicInteger(0);
        System.out.println("MyNumber before method Call:" + myNumber.get());
        PrimitivePassByReferenceSample temp = new PrimitivePassByReferenceSample() ;
        temp.changeMyNumber(myNumber);
        System.out.println("MyNumber After method Call:" + myNumber.get());


    }

     void changeMyNumber(AtomicInteger myNumber) {
        myNumber.getAndSet(100);

    }

}
Run Code Online (Sandbox Code Playgroud)

输出:

MyNumber before method Call:0

MyNumber After method Call:100
Run Code Online (Sandbox Code Playgroud)