Как сделать эквивалент 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  

в 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  

мой вопрос - каков эквивалентный код в Java, чтобы получить тот же вывод, что и код C++, учитывая, что Java передается по значению, а не проходит мимо ссылка?

6 97

6 ответов:

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

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

этот выбор потребует небольшого изменения в callsite в main, чтобы он читал, 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]);   
}

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)

вы можете увидеть это поведение в стандартных библиотеках. Например, коллекции.сортировка (); коллекции.шарканье(); Эти методы не возвращает новый список, но изменяет его объект аргумента.

    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)

сделать

class PassMeByRef { public int theValue; }

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

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

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

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