Чи можу я передати параметри за посиланням на Java?


Відповіді:


225

Java заплутаний, тому що все передається за значенням . Однак для параметра еталонного типу (тобто не параметра примітивного типу) саме посилання передається за значенням, отже, воно здається прохідним посиланням (і люди часто стверджують, що це є). Це не так, як показано в наступному:

Object o = "Hello";
mutate(o)
System.out.println(o);

private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o!

Буде надруковано Helloна консоль. Якщо ви хочете надрукувати вищевказаний код Goodbye, можна використовувати чітке посилання наступним чином:

AtomicReference<Object> ref = new AtomicReference<Object>("Hello");
mutate(ref);
System.out.println(ref.get()); //Goodbye!

private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); }

48
Також масив довжиною 1 може бути використаний для створення посилання, якщо ви дійсно хочете заплутати людей :)
Christoffer

2
AtomicReference та відповідні класи (AtomicInteger) найкращі для таких операцій
Naveen

3
AtomicReference - це надмірний набір, вам не обов’язково потрібний бар'єр пам’яті там, і вони можуть коштувати вам. У JRuby виникли проблеми з перформансом через мінливої ​​змінної, яка використовується при побудові об'єкта. Можливість використання масиву як спеціального посилання мені здається досить хорошим, і я бачив, що він використовувався не раз.
Елазар Лейбович

Я не думаю, що це заплутано, проте це нормальна поведінка. Варіанти типів існують на стеці, а типи посилань існують у купі, але посилання на референтні типи існують і на стеці. Таким чином, ви завжди працюєте зі значенням, яке є у стеці. Я вважаю, що питання тут було: чи можна передавати посилання зі стека, який вказує на якесь інше значення, яке також є на стеці. Або передати інший посилання, який вказує на деяку цінність, що живе на купі?
eomeroff

це я чудова інформація. я використовував масиви, але це здається чимось побудованим для роботи. я не знаю про продуктивність цього проти масивів, однак, якщо в критичному циклі продуктивності
steveh

65

Чи можу я передати параметри за посиланням на Java?

Немає.

Чому? У Java є лише один режим передачі аргументів методам: за значенням.

Примітка:

Для примітивів це легко зрозуміти: ви отримуєте копію значення.

Для всіх інших ви отримуєте копію посилання, і це називається також передачею за значенням.

Це все на цій фотографії:

введіть тут опис зображення


25

У Java на мовному рівні немає нічого подібного до ref . У Java існує лише проходження за значенням семантичне

З метою цікавості ви можете реалізувати подібний семантичний текст у Java, просто загорнувши об’єкти в клас, що змінюється:

public class Ref<T> {

    private T value;

    public Ref(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

    public void set(T anotherValue) {
        value = anotherValue;
    }

    @Override
    public String toString() {
        return value.toString();
    }

    @Override
    public boolean equals(Object obj) {
        return value.equals(obj);
    }

    @Override
    public int hashCode() {
        return value.hashCode();
    }
}

перевірка:

public void changeRef(Ref<String> ref) {
    ref.set("bbb");
}

// ...
Ref<String> ref = new Ref<String>("aaa");
changeRef(ref);
System.out.println(ref); // prints "bbb"

Чому б не використовувати натомість java.lang.ref.Reference?
Hardcoded

java.lang.ref.Reference не мають встановленого методу, він не змінює
dfa

чому б не використовувати AtomicReference(для не примітивів)? Або AtomicSomething(наприклад AtomicBoolean:) для примітивів?
Арвін

На жаль, <T> не приймає примітивні типи. Хотіли б зробити це: Ref <int>
jk7

1
@ jk7 Чи справді достатньо важливо використовуватись intзамість Integer, boolа не Booleanтак далі? Тобто класи обгортки (які автоматично розгортаються, якщо ви переживаєте за синтаксис) не працюють?
Пол Стеліан

18

Від Джеймса Гослінга в "Мова програмування Java":

"... У Java існує рівно один режим передачі параметрів - передайте значення - і це спрощує все."


2
Проголошення бога мови повинно бути оголошено відповіддю.
ingyhere

3
@ingyhere:: The pronouncement of the language god should be declared the answerНе дуже. Незважаючи на те, що творець Java думає чи вірить, абсолютна відповідь виходитиме з цитати з мовної специфікації.
paercebal

1
Насправді саме в JLS, у розділі 8.4.1 , і JLS цитує Гослінга як першого автора: "Коли метод або конструктор викликається (§15.12), значення фактичних виразів аргументу ініціалізують новостворені змінні параметра , кожна заявленого типу, перед виконанням корпусу методу чи конструктора. "
ingyhere

Саме так. Сарказм з низькими представниками представників не корисний.
duffymo

11

Я не думаю, що ти можеш. Вашим найкращим варіантом може бути інкапсуляція речі, яку ви хочете передати "за посиланням" на інший екземпляр класу, і передати посилання (зовнішній) клас (за значенням). Якщо ви бачите, що я маю на увазі ...

тобто ваш метод змінює внутрішній стан об'єкта, який він передається, який потім видно абоненту.


7

Java завжди передається за значенням.

При передачі примітиву це копія значення, а при передачі об'єкта - це копія опорного вказівника.


4

Інший варіант полягає у використанні масиву, наприклад, void method(SomeClass[] v) { v[0] = ...; } але 1) масив повинен бути ініціалізований перед викликом методу; 2) все ще не можна реалізувати, наприклад, метод swap таким чином ... Цей спосіб використовується в JDK, наприклад, в java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.