Как сделать эквивалент pass by reference для примитивов в Java

Этот код 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  

В С++ я могу передать переменную toyNumber как pass по ссылке, чтобы избежать теневого копирования, то есть создать копию той же переменной, что и ниже:

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

и вывод С++ будет следующим:

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

Мой вопрос: какой эквивалентный код в Java должен получать тот же результат, что и код С++, учитывая, что Java передается по значению, а не по ссылке?

Ответ 1

У вас есть несколько вариантов. Тот, который имеет наибольший смысл, зависит от того, что вы пытаетесь сделать.

Выбор 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
}

Этот выбор потребует небольшого изменения основного вызова, чтобы он читал, toyNumber = temp.play(toyNumber);.

Выбор 3: сделать его классом или статической переменной

Если две функции являются методами одного и того же класса или экземпляра класса, вы можете преобразовать toyNumber в переменную члена класса.

Выбор 4: Создайте один массив элементов типа int и передайте это

Это считается взломом, но иногда используется для возврата значений из встроенных вызовов класса.

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

Ответ 2

Java не вызов по ссылке вызов только по значению

Но все переменные типа объекта на самом деле являются указателями.

Итак, если вы используете Mutable Object, вы увидите нужное поведение

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)

Ответ 3

Сделайте

class PassMeByRef { public int theValue; }

затем передайте ссылку на экземпляр. Обратите внимание, что лучше избегать метода, который мутирует состояние через его аргументы, особенно в параллельном коде.

Ответ 4

Вы не можете передавать примитивы по ссылке в Java. Конечно, все переменные типа объекта на самом деле являются указателями, но мы называем их "ссылками", и они также всегда передаются по значению.

В ситуации, когда вам действительно нужно передать примитив по ссылке, люди иногда будут объявлять параметр как массив примитивного типа, а затем передавать массив из одного элемента в качестве аргумента. Таким образом, вы передаете ссылку int [1], и в методе вы можете изменить содержимое массива.

Ответ 5

Для быстрого решения вы можете использовать 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

Ответ 6

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