如何在 Java 中对原语执行相当于引用传递的操作

发布于 2024-10-31 08:25:19 字数 1348 浏览 2 评论 0原文

此 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);   
    }   
}  

将输出以下内容:

 
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;   
} 

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

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

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

This Java code:

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);   
    }   
}  

will output this:

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

In C++ I can pass the toyNumber variable as pass by reference to avoid shadowing i.e. creating a copy of the same variable as below:

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;   
} 

and the C++ output will be this:

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

My question is - What's the equivalent code in Java to get the same output as the C++ code, given that Java is pass by value rather than pass by reference?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

流年里的时光 2024-11-07 08:25:19

你有几种选择。最有意义的实际上取决于您想要做什么。

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

class MyToy {
  public int toyNumber;
}

,然后将对 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);   
}

选择 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
}

此选择需要对 main 中的调用点进行一些小更改,以便其读取: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]);   
}

You have several choices. The one that makes the most sense really depends on what you're trying to do.

Choice 1: make toyNumber a public member variable in a class

class MyToy {
  public int toyNumber;
}

then pass a reference to a MyToy to your method.

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);   
}

Choice 2: return the value instead of pass by reference

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
}

This choice would require a small change to the callsite in main so that it reads, toyNumber = temp.play(toyNumber);.

Choice 3: make it a class or static variable

If the two functions are methods on the same class or class instance, you could convert toyNumber into a class member variable.

Choice 4: Create a single element array of type int and pass that

This is considered a hack, but is sometimes employed to return values from inline class invocations.

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]);   
}
歌入人心 2024-11-07 08:25:19

Java 不是按引用调用,而是仅按值调用

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

因此,如果您使用可变对象,您将看到您想要的行为

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:
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)

您也可以在标准库中看到此行为。
例如 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:
[1, 2, 3, 4, 5]
[3, 4, 1, 5, 2]
[1, 2, 3, 4, 5]
BUILD SUCCESSFUL (total time: 0 seconds)

Java is not call by reference it is call by value only

But all variables of object type are actually pointers.

So if you use a Mutable Object you will see the behavior you want

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);
    }
}

Output of this code:

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)

You can see this behavior in Standard libraries too.
For example Collections.sort(); Collections.shuffle();
These methods does not return a new list but modifies it's argument object.

    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);

Output of this code:

run:
[1, 2, 3, 4, 5]
[3, 4, 1, 5, 2]
[1, 2, 3, 4, 5]
BUILD SUCCESSFUL (total time: 0 seconds)
失眠症患者 2024-11-07 08:25:19

创建 a

class PassMeByRef { public int theValue; }

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

Make a

class PassMeByRef { public int theValue; }

then pass a reference to an instance of it. Note that a method that mutates state through its arguments is best avoided, especially in parallel code.

孤芳又自赏 2024-11-07 08:25:19

为了快速解决方案,您可以使用 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);

    }

}

输出:

MyNumber before method Call:0

MyNumber After method Call:100

For a quick solution, you can use AtomicInteger or any of the atomic variables which will let you change the value inside the method using the inbuilt methods. Here is sample code:

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);

    }

}

Output:

MyNumber before method Call:0

MyNumber After method Call:100
平生欢 2024-11-07 08:25:19

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

在确实需要通过引用传递基元的情况下,人们有时会做的是将参数声明为基元类型的数组,然后传递单元素数组作为参数。因此,您传递一个引用 int[1],并且在该方法中,您可以更改数组的内容。

You cannot pass primitives by reference in Java. All variables of object type are actually pointers, of course, but we call them "references", and they are also always passed by value.

In a situation where you really need to pass a primitive by reference, what people will do sometimes is declare the parameter as an array of primitive type, and then pass a single-element array as the argument. So you pass a reference int[1], and in the method, you can change the contents of the array.

君勿笑 2024-11-07 08:25:19
public static void main(String[] args) {
    int[] toyNumber = new int[] {5};
    NewClass temp = new NewClass();
    temp.play(toyNumber);
    System.out.println("Toy number in main " + toyNumber[0]);
}

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]);
}
public static void main(String[] args) {
    int[] toyNumber = new int[] {5};
    NewClass temp = new NewClass();
    temp.play(toyNumber);
    System.out.println("Toy number in main " + toyNumber[0]);
}

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]);
}
杯别 2024-11-07 08:25:19

“Pass-by...”在JavaC 中保留。除此之外,如果您打算更改作为引用给出的原语的包装器实例,则可以通过反射来完成。 整数示例。

public class WrapperTest
{
    static void mute(Integer a)
    {
        try
        {
            Field fValue = a.getClass().getDeclaredField("value");
            fValue.setAccessible(true);
            fValue.set(a, 6);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        Integer z = 5;
        mute(z);
        System.out.println(z);
    }

}

输出为 6,如 C++ 示例中所示。反射是必需的,因为 Java 设计认为原始包装器是不可变的。否则,每个其他类都可以充当包装器,甚至是像 int[] 这样长度为 1 的数组。

"Pass-by..." is reserved in Java and C. Beyond this, if you intend to change a wrapper instance of a primitive given as reference, this is done by reflection. Example for Integer.

public class WrapperTest
{
    static void mute(Integer a)
    {
        try
        {
            Field fValue = a.getClass().getDeclaredField("value");
            fValue.setAccessible(true);
            fValue.set(a, 6);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        Integer z = 5;
        mute(z);
        System.out.println(z);
    }

}

Output is 6 as in your C++ example. Reflection is required, because Java design considers primitive wrappers as immutable. Else every other class can serve as wrapper, even an array like int[] of length 1 .

忆离笙 2024-11-07 08:25:19

我们在 checkPassByValue 中设置 a = 5,但它没有反映在 a 的值中。
类似地,当我们传递一个人时,我们可以使用 Person.setName 更新该人指向的数据,但是如果更改该人并使其引用一个新的 Person() 在这种情况下,更新将不会反映在主函数中

class Person {
    public String getName() {
        return name;
    }

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

    private String name;

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

}

public class PassByValueVsReference {
    public static void main(String[] args) {
        int a = 3;
        Person person = new Person("Foo");
        checkPassByValue(a, person);
        System.out.println(a);
        System.out.println(person.getName());
    }

    public static void checkPassByValue(int number, Person person) {
        number = 5;
        person.setName("Foo-updated");
        person = new Person("Foo_new reference");
    }
}

//C++ equivalent of checkPassByValue(int ,Person *);

We set a = 5 in the checkPassByValue but it is not reflected in the value of a.
Similarly, when we pass a person we can update the data where the person points to by using Person.setName however if change the person and make it refer to a new Person() in that case that update will not be reflected in the main function

class Person {
    public String getName() {
        return name;
    }

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

    private String name;

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

}

public class PassByValueVsReference {
    public static void main(String[] args) {
        int a = 3;
        Person person = new Person("Foo");
        checkPassByValue(a, person);
        System.out.println(a);
        System.out.println(person.getName());
    }

    public static void checkPassByValue(int number, Person person) {
        number = 5;
        person.setName("Foo-updated");
        person = new Person("Foo_new reference");
    }
}

//C++ equivalent of checkPassByValue(int ,Person *);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文