Является ли Java «передачей по ссылке» или «передачей по значению»? - PullRequest
5963 голосов
/ 03 сентября 2008

Я всегда думал, что Java была передача по ссылке .

Однако я видел пару постов в блоге (например, этот блог ), в которых утверждается, что это не так.

Я не думаю, что понимаю разницу, которую они проводят.

Какое объяснение?

Ответы [ 79 ]

2 голосов
/ 18 ноября 2017

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

1 голос
/ 30 апреля 2019

Короче говоря:

  1. Не примитивы: Java передает Значение ссылки .
  2. Примитивы: просто значение.

Конец.

(2) слишком просто. Теперь, если вы хотите подумать о том, что (1) означает, представьте, что у вас есть класс Apple:

class Apple {
    private double weight;
    public Apple(double weight) {
        this.weight = weight;
    }
    // getters and setters ...

}

затем, когда вы передаете экземпляр этого класса методу main:

class Main {
    public static void main(String[] args) {
        Apple apple = new Apple(3.14);
        transmogrify(apple);
        System.out.println(apple.getWeight()+ " the goose drank wine...";

    }

    private static void transmogrify(Apple apple) {
        // does something with apple ...
        apple.setWeight(apple.getWeight()+0.55);
    }
}

оу ... но вы, вероятно, знаете, что вам интересно, что происходит, когда вы делаете что-то вроде этого:

class Main {
    public static void main(String[] args) {
        Apple apple = new Apple(3.14);
        transmogrify(apple);
        System.out.println("Who ate my: "+apple.getWeight()); // will it still be 3.14? 

    }

    private static void transmogrify(Apple apple) {
        // assign a new apple to the reference passed...
        apple = new Apple(2.71);
    }


}
1 голос
/ 14 ноября 2013

Язык программирования Java передает аргументы только по значению, то есть вы не можете изменить значение аргумента в вызывающем методе изнутри вызываемый метод.


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


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

  • Во-первых, способность изменить вещь перешла в Метод применяется только к объектам, а не к примитивным значениям.

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


The following code example illustrates this point:
1 public class PassTest {
2
3   // Methods to change the current values
4   public static void changeInt(int value) {
5     value = 55;
6  }
7   public static void changeObjectRef(MyDate ref) {
8     ref = new MyDate(1, 1, 2000);
9  }
10   public static void changeObjectAttr(MyDate ref) {
11     ref.setDay(4);
12   }
13
14 public static void main(String args[]) {
15     MyDate date;
16     int val;
17
18     // Assign the int
19     val = 11;
20     // Try to change it
21     changeInt(val);
22     // What is the current value?
23     System.out.println("Int value is: " + val);
24
25 // Assign the date
26     date = new MyDate(22, 7, 1964);
27     // Try to change it
28     changeObjectRef(date);
29     // What is the current value?
30 System.out.println("MyDate: " + date);
31
32 // Now change the day attribute
33     // through the object reference
34     changeObjectAttr(date);
35     // What is the current value?
36 System.out.println("MyDate: " + date);
37   }
38 }

This code outputs the following:
java PassTest
Int value is: 11
MyDate: 22-7-1964
MyDate: 4-7-1964
The MyDate object is not changed by the changeObjectRef method;
however, the changeObjectAttr method changes the day attribute of the
MyDate object.
1 голос
/ 24 ноября 2015

В соответствии с C ++ ТЕРМИНОЛОГИЯ:

  1. Примитивные типы и их обёртки - Pass by Value
  2. Другие сложные типы данных - передача по ссылке

(Хотя Java полностью Pass by Value, во втором случае она передает ссылку на объект, и в этом случае значение объекта, если оно было изменено, отражается в основной функции, и поэтому я назвал его Pass by Reference в соответствии с C ++ Терминология.) Если вы родом из C ++, то Java передается по значению для примитивных типов и их классов Wrapper, таких как int, Integer, bool, Boolean, т. Е. Если вы передаете значение этих типов данных, в исходной функции изменений не будет. Для всех других типов данных java просто передает их, и если любое изменение сделано, изменение можно увидеть в исходной функции (это можно назвать передачей по ссылке в соответствии с терминологией c ++)

0 голосов
/ 24 апреля 2019

Эта статья запутана.

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

Передается ли язык по значению или по ссылке? Почему мы задаем этот вопрос?

Вся проблема возникает при вызове метода. Такой метод определяется параметрами и вызывается с аргументами.

Полезно проводить различие между параметром и аргументом. Параметр - это имя полученной вещи, указанное при определении метода. Аргумент - это имя отправленной вещи, указанное при вызове метода.

Любой контент, хранящийся в памяти, имеет адрес для доступа. Этот адрес содержимого называется ссылкой. С помощью ссылки можно получить доступ к контенту. Если ссылка дается на уровень, то этот уровень может получать доступ и обновлять ссылочный контент. Если ссылка дается на метод, то этот метод может также получить доступ и обновить этот ссылочный контент.

Что происходит при "передаче" аргумента в параметр метода? Создается копия аргумента и передается параметру метода.

Что мы понимаем, когда говорим «передача по значению» и «передача по ссылке»? При использовании слова «ценность» мы понимаем фактическое содержание, которое хранится, скажем, чье-то имя. При использовании слова «ссылка» мы понимаем адрес памяти, указывающий на «значение».

Итак, когда мы говорим «передать по значению», мы понимаем, что аргумент, который мы передаем в параметр метода, является некоторым содержимым. И когда мы говорим «передать по ссылке», мы понимаем, что аргумент, который мы передаем в параметр метода, является адресом памяти, указывающим на некоторый контент.

Если передается какой-либо контент, то копия этого контента создается и передается методу. Поскольку предоставленное содержимое является копией, нет риска изменить исходное содержимое.

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

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

То, что копия ссылки сделана до того, как передана параметру метода, не делает эту ссылку значением.

Своп-тест не является решающим показателем.

Если объект вне метода может быть изменен изнутри метода при передаче его методу, то передача осуществляется по ссылке.

Документация по Java и множество статей в лучшем случае сбивают с толку, а в худшем - ошибочны.

Мои два цента.

0 голосов
/ 24 января 2019

Очень просто! Переменная будет передана по значению, если это примитив, и по ссылке, если это объект.

Вот и все

0 голосов
/ 28 августа 2018

Простой ответ для новичка

Если вы передаете сложный объект (например, собаку, как это, видимо, является распространенным примером), он аналогичен передаче ссылки. Если вы передаете поле сложного Объекта (например, только имя собаки), оно аналогично передаче значения (изменение его не изменит собаку / родителя поля).

Обратите внимание, что Объект, который не является "сложным" (не похожим на нашу собаку), как Integer или String, передается по значению. Поэтому, даже если они являются объектами со всем, что вы можете для них сделать, их нельзя изменить внутри метода ... Да, это неправильно и не имеет никакого смысла ...

Пример (не собака):

public class HelloWorld {
    private Integer i;
    private String s;
    private Boolean b;

    public static void main(String[] args) {
        HelloWorld h = new HelloWorld();

        h.s = "Bill";
        h.ModMe(h.s);
        h.i = 2;
        h.ModMe(h.i);
        h.b = true;
        h.ModMe(h.b);
        System.out.println(h.s + " " + h.i + " " + h.b);

        h.ModMe(h);
        System.out.println(h.s + " " + h.i + " " + h.b);

        String test = "TEST";
        h.ModMe(test);
        System.out.println(test);
    }

    public void ModMe(Object o) {
        if (o instanceof HelloWorld) {
            ((HelloWorld) o).i = (int) Math.pow(((HelloWorld) o).i, 2);
            ((HelloWorld) o).b = !((HelloWorld) o).b;
            ((HelloWorld) o).s = ((HelloWorld) o).s.concat(" modded successfully");
        } else if (o instanceof Integer) {
            o = (Integer) o + (Integer) o;
        } else if (o instanceof String) {
            o = ((String) o).concat(" is modified.");
        } else if (o instanceof Boolean) {
            o = !(Boolean) o;
        }
    }
}

Если вы запустите, объект h будет изменен, если вы используете весь объект в качестве аргумента, но не поля s i или b, если вы используете их только в качестве аргумента. если вы отладите это, вы заметите, что для полей идентификатор объекта изменится, как только вы запустите строку, в которой значение будет изменено. Таким образом, он будет делать то же самое, что и "new Integer", "new String" и "new Boolean" автоматически.

0 голосов
/ 03 декабря 2013

Java передает ссылки на объекты по значению.

Таким образом, если какая-либо модификация сделана для Объекта, на который указывает ссылочный аргумент, он будет отражен обратно на исходный объект.

Но если аргумент ссылки указывает на другой Объект, исходная ссылка будет указывать на исходный Объект.

0 голосов
/ 20 февраля 2018

TL; DR: минимальный пример:

package foobar;
import java.util.ArrayList;

public class FooBar {

  public static void main(String[] args) {
    ArrayList<Integer> list1 = new ArrayList<>(); // An object.
    list1.add(1);

    ArrayList<Integer> list2 = new ArrayList<>(); // Another object.
    list2.add(2);

    int x = 42; // A primitive (same with Integer).

    sideEffects(list1, list2, x);

    System.out.println(list1); // Output: [1]     (unchanged)
    System.out.println(list2); // Output: [2, 3]  (changed !)
    System.out.println(x);     // Output: 42      (not changed)
  }

  private static void sideEffects(ArrayList<Integer> list1, ArrayList<Integer> list2, int x) {
    list1 = list2;
    list1.add(3);
    x = 21;
  }
}
...