Вопрос:

Является ли Java «передачей по ссылке» или «передачей по значению»?

java methods parameter-passing pass-by-reference pass-by-value

1857260 просмотра

30 ответа

2355 Репутация автора

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

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

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

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

Автор: user4315 Источник Размещён: 02.09.2008 08:14

Ответы (30)


640 плюса

27529 Репутация автора

Java всегда передается по значению, без исключений, никогда .

Так почему же это может смущать любого, кто верит, что Java передается по ссылке, или думает, что у него есть пример того, как Java действует как передача по ссылке? Ключевым моментом является то, что Java никогда не обеспечивает прямого доступа к значениям самих объектов ни при каких обстоятельствах. Единственный доступ к объектам - через ссылку на этот объект. Поскольку доступ к объектам Java всегда осуществляется через ссылку, а не напрямую, обычно говорят о полях, переменных и аргументах методов как об объектах , когда педантично они являются только ссылками на объекты .Путаница проистекает из этого (строго говоря, неверного) изменения в номенклатуре.

Итак, при вызове метода

  • Для аргументов примитива ( int, longи т. Д.) Передача по значению является фактическим значением примитива (например, 3).
  • Для объектов передача по значению является значением ссылки на объект .

Так что если у вас есть doSomething(foo)и public void doSomething(Foo foo) { .. }два Foos скопировали ссылки, которые указывают на одни и те же объекты.

Естественно, передача по значению ссылки на объект очень похожа (и практически не отличается от) передачи объекта по ссылке.

Автор: SCdF Размещён: 02.09.2008 08:19

310 плюса

65529 Репутация автора

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

Таким образом, вы не можете изменить ссылку, которая будет передана.

Автор: ScArcher2 Размещён: 02.09.2008 08:20

156 плюса

54155 Репутация автора

По сути, переназначение параметров объекта не влияет на аргумент, например,

private void foo(Object bar) {
    bar = null;
}

public static void main(String[] args) {
    String baz = "Hah!";
    foo(baz);
    System.out.println(baz);
}

распечатает "Hah!"вместо null. Причина, по которой это работает, заключается в том, что barэто копия значения baz, которое является просто ссылкой на "Hah!". Если бы это было само собой фактическое задание, тогда fooбы переопределена bazв null.

Автор: Hank Gay Размещён: 02.09.2008 08:21

160 плюса

4367 Репутация автора

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

Автор: John Channing Размещён: 02.09.2008 08:23

5498 плюса

6053 Репутация автора

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

Это выглядит так:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    // we pass the object to foo
    foo(aDog);
    // aDog variable is still pointing to the "Max" dog when foo(...) returns
    aDog.getName().equals("Max"); // true
    aDog.getName().equals("Fifi"); // false
    aDog == oldDog; // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // change d inside of foo() to point to a new Dog instance "Fifi"
    d = new Dog("Fifi");
    d.getName().equals("Fifi"); // true
}

В приведенном выше примере aDog.getName()все еще вернется "Max". Значение в aDogпределах mainне изменяется в функции fooс в Dog "Fifi"качестве ссылки на объект передается по значению. Если бы он был передан по ссылке, то после вызова к возвращается aDog.getName()in .main"Fifi"foo

Точно так же:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
    // but it is still the same dog:
    aDog == oldDog; // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // this changes the name of d to be "Fifi"
    d.setName("Fifi");
}

В приведенном выше примере Fifiэто имя собаки после вызова, foo(aDog)потому что имя объекта было установлено внутри foo(...). Любые операции , которые fooвыполняют на dтаковы , что для всех практических целей, они выполняются на aDog, но это не возможно изменить значение переменного aDogсам.

Автор: erlando Размещён: 02.09.2008 08:25

23 плюса

4635 Репутация автора

Короче говоря, у объектов Java есть некоторые очень специфические свойства.

В общем, Java , имеет примитивные типы ( int, bool, char, double, и т.д.), которые передаются непосредственно по значению. Тогда у Java есть объекты (все, что происходит от java.lang.Object). Объекты на самом деле всегда обрабатываются с помощью ссылки (ссылка - это указатель, который вы не можете коснуться). Это означает, что, по сути, объекты передаются по ссылке, так как ссылки обычно не интересны. Это, однако, означает, что вы не можете изменить объект, на который указывает объект, так как сама ссылка передается по значению.

Это звучит странно и сбивает с толку? Давайте рассмотрим, как C реализует передачу по ссылке и передачу по значению. В С соглашением по умолчанию является передача по значению. void foo(int x)передает int по значению. void foo(int *x)это функция , которая не желает , чтобы int a, но указатель на междунар: foo(&a). Можно использовать это с &оператором для передачи адреса переменной.

Отнесите это на C ++, и у нас есть ссылки. Ссылки в основном (в этом контексте) синтаксический сахар, который скрывает указатель части уравнения: void foo(int &x)вызывается foo(a), когда сам компилятор знает, что это ссылка, и адрес не-ссылки aдолжен быть передан. В Java все переменные, ссылающиеся на объекты, на самом деле относятся к ссылочному типу, фактически вызывая вызов по ссылке для большинства целей и задач без детального контроля (и сложности), предоставляемого, например, C ++.

Автор: Paul de Vrieze Размещён: 02.09.2008 08:53

36 плюса

16939 Репутация автора

The distinction, or perhaps just the way I remember as I used to be under the same impression as the original poster is this: Java is always pass by value. All objects( in Java, anything except for primitives) in Java are references. These references are passed by value.

Автор: shsteimer Размещён: 03.09.2008 07:42

35 плюса

9665 Репутация автора

Как уже упоминали многие люди, Java всегда передается по значению

Вот еще один пример, который поможет вам понять разницу ( классический пример обмена ):

public class Test {
  public static void main(String[] args) {
    Integer a = new Integer(2);
    Integer b = new Integer(3);
    System.out.println("Before: a = " + a + ", b = " + b);
    swap(a,b);
    System.out.println("After: a = " + a + ", b = " + b);
  }

  public static swap(Integer iA, Integer iB) {
    Integer tmp = iA;
    iA = iB;
    iB = tmp;
  }
}

Печать:

До: а = 2, б = 3
После: а = 2, б = 3

Это происходит потому, что iA и iB являются новыми локальными ссылочными переменными, которые имеют одинаковое значение переданных ссылок (они указывают на a и b соответственно). Таким образом, попытка изменить ссылки iA или iB изменится только в локальной области, а не вне этого метода.

Автор: pek Размещён: 03.09.2008 08:01

29 плюса

254 Репутация автора

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

public class PassByCopy{
    public static void changeName(Dog d){
        d.name = "Fido";
    }
    public static void main(String[] args){
        Dog d = new Dog("Maxx");
        System.out.println("name= "+ d.name);
        changeName(d);
        System.out.println("name= "+ d.name);
    }
}
class Dog{
    public String name;
    public Dog(String s){
        this.name = s;
    }
}

вывод Java PassByCopy:

имя = макс
имя = фидо

Примитивные классы-обертки и строки являются неизменяемыми, поэтому любой пример, использующий эти типы, не будет работать так же, как другие типы / объекты.

Автор: SWD Размещён: 08.09.2008 02:48

25 плюса

11520 Репутация автора

Я создал ветку, посвященную этим вопросам для любых языков программирования здесь .

Ява также упоминается . Вот краткое резюме:

  • Java передает его параметры по значению
  • «по значению» это единственный способ в Java передать параметр методу
  • использование методов из объекта, заданного в качестве параметра, изменит объект, так как ссылки указывают на исходные объекты. (если этот метод сам изменяет некоторые значения)
Автор: sven Размещён: 08.09.2008 02:54

2909 плюса

26194 Репутация автора

Я только что заметил, что вы ссылались на мою статью .

Спецификация Java говорит, что все в Java передается по значению. В Java нет такой вещи, как «передача по ссылке».

Ключом к пониманию этого является то, что

Dog myDog;

это не собака; это на самом деле указатель на собаку.

Что это значит, когда у вас есть

Dog myDog = new Dog("Rover");
foo(myDog);

по сути, вы передаете адрес созданного Dogобъекта fooметоду.

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

Предположим, что Dogобъект находится по адресу памяти 42. Это означает, что мы передаем 42 методу.

если метод был определен как

public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}

давайте посмотрим на то, что происходит.

  • для параметра someDogустановлено значение 42
  • на линии "ААА"
    • someDogследует к Dogнему указывает ( Dogобъект по адресу 42)
    • что Dog(тот, по адресу 42) попросили изменить его имя на Макс
  • на линии "ВВВ"
    • новый Dogсоздан. Допустим, он по адресу 74
    • мы назначаем параметр someDog74
  • на линии "CCC"
    • SomeDog следует на Dogэто указывает ( Dogобъект по адресу 74)
    • что Dog(тот, по адресу 74) попросили изменить его имя на Rowlf
  • тогда мы вернемся

Теперь давайте подумаем о том, что происходит вне метода:

Изменился myDog?

Там ключ.

Помня, что myDogэто указатель , а не факт Dog, ответ НЕТ. myDogпо-прежнему имеет значение 42; он по-прежнему указывает на оригинал Dog(но обратите внимание, что из-за строки «AAA» его имя теперь «Макс» - все тот же Dog; myDogзначение не изменилось.)

Совершенно верно следовать за адресом и изменять то, что в конце этого; однако это не меняет переменную.

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

В C ++, Ada, Pascal и других языках, которые поддерживают передачу по ссылке, вы действительно можете изменить переданную переменную.

Если бы у Java была семантика передачи по ссылке, то fooметод, который мы определили выше, изменился бы там, куда myDogуказывал, когда он был назначен someDogв строке BBB.

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

Автор: Scott Stanchfield Размещён: 16.09.2008 02:37

181 плюса

39480 Репутация автора

Чтобы показать контраст, сравните следующие фрагменты C ++ и Java :

В C ++: Примечание: плохой код - утечки памяти! Но это демонстрирует суть.

void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef)
{
    val = 7; // Modifies the copy
    ref = 7; // Modifies the original variable
    obj.SetName("obj"); // Modifies the copy of Dog passed
    objRef.SetName("objRef"); // Modifies the original Dog passed
    objPtr->SetName("objPtr"); // Modifies the original Dog pointed to 
                               // by the copy of the pointer passed.
    objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                   // leaving the original object alone.
    objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to 
                                    // by the original pointer passed. 
    objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed
}

int main()
{
    int a = 0;
    int b = 0;
    Dog d0 = Dog("d0");
    Dog d1 = Dog("d1");
    Dog *d2 = new Dog("d2");
    Dog *d3 = new Dog("d3");
    cppMethod(a, b, d0, d1, d2, d3);
    // a is still set to 0
    // b is now set to 7
    // d0 still have name "d0"
    // d1 now has name "objRef"
    // d2 now has name "objPtr"
    // d3 now has name "newObjPtrRef"
}

В Java

public static void javaMethod(int val, Dog objPtr)
{
   val = 7; // Modifies the copy
   objPtr.SetName("objPtr") // Modifies the original Dog pointed to 
                            // by the copy of the pointer passed.
   objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                  // leaving the original object alone.
}

public static void main()
{
    int a = 0;
    Dog d0 = new Dog("d0");
    javaMethod(a, d0);
    // a is still set to 0
    // d0 now has name "objPtr"
}

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

Автор: Eclipse Размещён: 17.09.2008 05:38

109 плюса

36155 Репутация автора

Суть дела в том, что слово « ссылка» в выражении «передача по ссылке» означает нечто совершенно отличное от обычного значения слова « ссылка» в Java.

Обычно в Java ссылка означает ссылку на объект . Но технические термины, передаваемые по ссылке / значению из теории языка программирования, говорят о ссылке на ячейку памяти, содержащую переменную , что является чем-то совершенно другим.

Автор: JacquesB Размещён: 12.01.2009 08:50

47 плюса

12581 Репутация автора

You can never pass by reference in Java, and one of the ways that is obvious is when you want to return more than one value from a method call. Consider the following bit of code in C++:

void getValues(int& arg1, int& arg2) {
    arg1 = 1;
    arg2 = 2;
}
void caller() {
    int x;
    int y;
    getValues(x, y);
    cout << "Result: " << x << " " << y << endl;
}

Sometimes you want to use the same pattern in Java, but you can't; at least not directly. Instead you could do something like this:

void getValues(int[] arg1, int[] arg2) {
    arg1[0] = 1;
    arg2[0] = 2;
}
void caller() {
    int[] x = new int[1];
    int[] y = new int[1];
    getValues(x, y);
    System.out.println("Result: " + x[0] + " " + y[0]);
}

As was explained in previous answers, in Java you're passing a pointer to the array as a value into getValues. That is enough, because the method then modifies the array element, and by convention you're expecting element 0 to contain the return value. Obviously you can do this in other ways, such as structuring your code so this isn't necessary, or constructing a class that can contain the return value or allow it to be set. But the simple pattern available to you in C++ above is not available in Java.

Автор: Jared Oberhaus Размещён: 08.03.2009 06:28

53 плюса

3025 Репутация автора

As far as I know, Java only knows call by value. This means for primitive datatypes you will work with an copy and for objects you will work with an copy of the reference to the objects. However I think there are some pitfalls; for example, this will not work:

public static void swap(StringBuffer s1, StringBuffer s2) {
    StringBuffer temp = s1;
    s1 = s2;
    s2 = temp;
}


public static void main(String[] args) {
    StringBuffer s1 = new StringBuffer("Hello");
    StringBuffer s2 = new StringBuffer("World");
    swap(s1, s2);
    System.out.println(s1);
    System.out.println(s2);
}

Это заполнит Hello World, а не World Hello, потому что в функции подкачки вы используете copys, которые не влияют на ссылки в основном. Но если ваши объекты не являются неизменяемыми, вы можете изменить это, например:

public static void appendWorld(StringBuffer s1) {
    s1.append(" World");
}

public static void main(String[] args) {
    StringBuffer s = new StringBuffer("Hello");
    appendWorld(s);
    System.out.println(s);
}

Это заполнит Hello World в командной строке. Если вы измените StringBuffer на String, он выдаст только Hello, потому что String неизменен. Например:

public static void appendWorld(String s){
    s = s+" World";
}

public static void main(String[] args) {
    String s = new String("Hello");
    appendWorld(s);
    System.out.println(s);
}

Однако вы можете создать оболочку для String, например, такую, которая позволит использовать его со строками:

class StringWrapper {
    public String value;

    public StringWrapper(String value) {
        this.value = value;
    }
}

public static void appendWorld(StringWrapper s){
    s.value = s.value +" World";
}

public static void main(String[] args) {
    StringWrapper s = new StringWrapper("Hello");
    appendWorld(s);
    System.out.println(s.value);
}

редактировать: я считаю, что это также причина для использования StringBuffer, когда дело доходит до «добавления» двух строк, потому что вы можете изменить исходный объект, что вы не можете с неизменными объектами, такими как String.

Автор: kukudas Размещён: 01.04.2009 09:33

25 плюса

39 Репутация автора

Несколько исправлений к некоторым постам.

C не поддерживает передачу по ссылке. ВСЕГДА передается по значению. C ++ поддерживает передачу по ссылке, но не используется по умолчанию и довольно опасен.

Неважно, какое значение в Java: примитив или адрес (примерно) объекта, оно ВСЕГДА передается по значению.

Если объект Java "ведет себя" так, как его передают по ссылке, это свойство изменчивости и не имеет абсолютно никакого отношения к механизмам передачи.

Я не уверен, почему это так сбивает с толку, возможно, потому, что так много «программистов» на Java не обучены формально и, следовательно, не понимают, что в действительности происходит в памяти?

Автор: Rusty Shackleford Размещён: 26.12.2009 08:19

146 плюса

303908 Репутация автора

Я не могу поверить, что никто еще не упомянул Барбару Лисков. Когда она разработала CLU в 1974 году, она столкнулась с той же проблемой терминологии, и она изобрела термин вызов путем разделения (также известный как вызов посредством разделения объектов и вызов по объекту ) для этого конкретного случая «вызов по значению, где значение равно ссылка".

Автор: Jörg W Mittag Размещён: 07.09.2010 10:07

706 плюса

9790 Репутация автора

Это даст вам некоторое представление о том, как на самом деле работает Java, до такой степени, что в вашем следующем обсуждении передачи Java по ссылке или по значению вы просто улыбнетесь :-)

Шаг первый, пожалуйста, удалите из памяти это слово, которое начинается с 'p' "_ _ _ _ _ _ _", особенно если вы пришли из других языков программирования. Java и 'p' не могут быть записаны в одной книге, на форуме или даже в txt.

Шаг второй Помните, что когда вы передаете Object в метод, вы передаете ссылку на Object, а не сам объект.

  • Ученик : Магистр, означает ли это, что Java передается по ссылке?
  • Мастер : Кузнечик, №

Теперь подумайте о том, что ссылка / переменная объекта делает / является:

  1. Переменная содержит биты, которые сообщают JVM, как добраться до указанного объекта в памяти (Heap).
  2. При передаче аргументов методу вы НЕ передаете ссылочную переменную, а копируете биты в ссылочной переменной . Как то так: 3bad086a. 3bad086a представляет способ добраться до пропущенного объекта.
  3. Итак, вы просто передаете 3bad086a, что это значение ссылки.
  4. Вы передаете значение ссылки, а не саму ссылку (и не объект).
  5. Это значение фактически копируется и присваивается методу .

В следующем (пожалуйста, не пытайтесь скомпилировать / выполнить это ...):

1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7.     anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }

Что происходит?

  • Переменная person создается в строке # 1 и в начале имеет значение null.
  • Новый объект Person создается в строке # 2, сохраняется в памяти, а переменной person дается ссылка на объект Person. То есть его адрес. Допустим, 3bad086a.
  • Переменная person, содержащая адрес объекта, передается функции в строке # 3.
  • В строке № 4 вы можете прослушать звук тишины
  • Проверьте комментарий в строке № 5
  • Локальная переменная метода - anotherReferenceToTheSamePersonObject - создается, а затем появляется волшебство в строке # 6:
    • Переменная / эталонное лицо копируется побитно и передается в другойReferenceToTheSamePersonObject внутри функции.
    • Новые экземпляры Person не создаются.
    • И " person ", и " anotherReferenceToTheSamePersonObject " содержат одно и то же значение 3bad086a.
    • Не пытайтесь это сделать, но person == anotherReferenceToTheSamePersonObject будет истинным.
    • Обе переменные имеют ИДЕНТИЧНЫЕ КОПИИ ссылки, и они обе ссылаются на один и тот же объект Person, ОДИН ЖЕ объект в куче и НЕ КОПИЮ.

Одна картинка стоит тысячи слов:

Передать по значению

Обратите внимание, что стрелки anotherReferenceToTheSamePersonObject направлены к объекту, а не к переменной person!

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

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

Вы всегда передаете копию битов значения ссылки!

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

Java передается по значению, потому что внутри метода вы можете изменять ссылочный объект столько раз, сколько захотите, но как бы вы ни старались, вы никогда не сможете изменить переданную переменную, которая будет продолжать ссылаться (не p _ _ _) _ _ _ _) один и тот же объект, несмотря ни на что!


Приведенная выше функция changeName никогда не сможет изменить фактическое содержимое (значения битов) переданной ссылки. Другими словами, changeName не может заставить человека ссылаться на другой объект.


Конечно, вы можете сократить его и просто сказать, что Java передается по значению!

Автор: Marsellus Wallace Размещён: 12.08.2011 01:22

1625 плюса

88049 Репутация автора

Java всегда передает аргументы по значению, а не по ссылке.


Позвольте мне объяснить это на примере :

public class Main{
     public static void main(String[] args){
          Foo f = new Foo("f");
          changeReference(f); // It won't change the reference!
          modifyReference(f); // It will modify the object that the reference variable "f" refers to!
     }
     public static void changeReference(Foo a){
          Foo b = new Foo("b");
          a = b;
     }
     public static void modifyReference(Foo c){
          c.setAttribute("c");
     }
}

Я объясню это по шагам:

  1. Объявить ссылку с именем fтипа Fooи назначить ей новый объект типа Fooс атрибутом "f".

    Foo f = new Foo("f");
    

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

  2. Со стороны метода объявляется ссылка на тип Fooс именем, aи она изначально присваивается null.

    public static void changeReference(Foo a)
    

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

  3. Когда вы вызываете метод changeReference, ссылке aбудет присвоен объект, который передается в качестве аргумента.

    changeReference(f);
    

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

  4. Объявить ссылку с именем bтипа Fooи назначить ей новый объект типа Fooс атрибутом "b".

    Foo b = new Foo("b");
    

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

  5. a = bсоздает новое назначение для ссылки a, а не f для объекта, чьим атрибутом является "b".

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


  6. Когда вы вызываете modifyReference(Foo c)метод, создается ссылка cи назначается объект с атрибутом "f".

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

  7. c.setAttribute("c");изменит атрибут объекта, на который cуказывает ссылка , и тот же объект, на который fуказывает ссылка .

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

Надеюсь, теперь вы понимаете, как передача объектов в качестве аргументов работает в Java :)

Автор: Eng.Fouad Размещён: 14.09.2012 06:22

53 плюса

444 Репутация автора

Нет, это не передача по ссылке.

Java передается по значению в соответствии со спецификацией языка Java:

Когда метод или конструктор вызывают (§15.12), значения фактических выражений аргумента инициализируют вновь созданные переменные параметра , каждый из объявленного типа, перед выполнением тела метода или конструктора. Идентификатор, который появляется в DeclaratorId, может использоваться как простое имя в теле метода или конструктора для ссылки на формальный параметр .

Автор: G Flores Размещён: 12.10.2012 03:00

31 плюса

166 Репутация автора

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

public void test() {
    MyClass obj = null;
    init(obj);
    //After calling init method, obj still points to null
    //this is because obj is passed as value and not as reference.
}
private void init(MyClass objVar) {
    objVar = new MyClass();
}
Автор: Gaurav Размещён: 10.07.2013 06:31

222 плюса

1060 Репутация автора

Я чувствую, что спор о «передача по ссылке против передачи по значению» не является супер-полезным.

Если вы говорите: «Java является передачей по любому (ссылка / значение)», в любом случае вы не дадите полного ответа. Вот некоторая дополнительная информация, которая, надеюсь, поможет понять, что происходит в памяти.

Ускоренный курс по стеку / куче, прежде чем мы перейдем к реализации Java: значения идут и выходят из стека хорошим упорядоченным образом, как стопка тарелок в кафетерии. Память в куче (также известная как динамическая память) является случайной и дезорганизованной. JVM просто находит место, где только может, и освобождает его, поскольку переменные, которые его используют, больше не нужны.

Хорошо. Прежде всего, локальные примитивы идут в стек. Итак, этот код:

int x = 3;
float y = 101.1f;
boolean amIAwesome = true;

Результаты в этом:

примитивы в стеке

When you declare and instantiate an object. The actual object goes on the heap. What goes on the stack? The address of the object on the heap. C++ programmers would call this a pointer, but some Java developers are against the word "pointer". Whatever. Just know that the address of the object goes on the stack.

Like so:

int problems = 99;
String name = "Jay-Z";

ab * 7ch не один!

An array is an object, so it goes on the heap as well. And what about the objects in the array? They get their own heap space, and the address of each object goes inside the array.

JButton[] marxBros = new JButton[3];
marxBros[0] = new JButton("Groucho");
marxBros[1] = new JButton("Zeppo");
marxBros[2] = new JButton("Harpo");

братья маркс

So, what gets passed in when you call a method? If you pass in an object, what you're actually passing in is the address of the object. Some might say the "value" of the address, and some say it's just a reference to the object. This is the genesis of the holy war between "reference" and "value" proponents. What you call it isn't as important as that you understand that what's getting passed in is the address to the object.

private static void shout(String name){
    System.out.println("There goes " + name + "!");
}

public static void main(String[] args){
    String hisName = "John J. Jingleheimerschmitz";
    String myName = hisName;
    shout(myName);
}

Создается одна строка, и место для нее выделяется в куче, а адрес строки сохраняется в стеке и получает идентификатор hisName, поскольку адрес второй строки совпадает с первым, новая строка не создается и новое пространство кучи не выделяется, но в стеке создается новый идентификатор. Затем мы вызываем shout(): создается новый кадр стека и создается новый идентификатор, nameи ему присваивается адрес уже существующей строки.

ла да ди да да да да

Итак, ценность, ссылка? Вы говорите "картофель".

Автор: cutmancometh Размещён: 11.09.2013 11:34

77 плюса

824 Репутация автора

Java всегда передается по значению, а не по ссылке

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

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

Передача по ссылке (также называемая передачей по адресу) означает, что копия адреса фактического параметра сохраняется .

Иногда Java может дать иллюзию передачи по ссылке. Давайте посмотрим, как это работает, используя пример ниже:

public class PassByValue {
    public static void main(String[] args) {
        Test t = new Test();
        t.name = "initialvalue";
        new PassByValue().changeValue(t);
        System.out.println(t.name);
    }

    public void changeValue(Test f) {
        f.name = "changevalue";
    }
}

class Test {
    String name;
}

Выход этой программы:

changevalue

Давайте разберемся шаг за шагом:

Test t = new Test();

Как мы все знаем, он создаст объект в куче и вернет значение ссылки обратно в t. Например, предположим, что значение t равно 0x100234(мы не знаем фактическое внутреннее значение JVM, это всего лишь пример).

первая иллюстрация

new PassByValue().changeValue(t);

При передаче ссылки t в функцию она не будет напрямую передавать фактическое значение ссылки объекта test, но создаст копию t и затем передаст ее функции. Поскольку он передается по значению , он передает копию переменной, а не фактическую ссылку на нее. Поскольку мы сказали, что значение t было 0x100234, и t, и f будут иметь одинаковое значение, и, следовательно, они будут указывать на один и тот же объект.

вторая иллюстрация

Если вы измените что-либо в функции, используя ссылку f, это изменит существующее содержимое объекта. Вот почему мы получили вывод changevalue, который обновляется в функции.

Чтобы понять это более четко, рассмотрим следующий пример:

public class PassByValue {
    public static void main(String[] args) {
        Test t = new Test();
        t.name = "initialvalue";
        new PassByValue().changeRefence(t);
        System.out.println(t.name);
    }

    public void changeRefence(Test f) {
        f = null;
    }
}

class Test {
    String name;
}

Будет ли это бросить NullPointerException? Нет, потому что он передает только копию ссылки. В случае передачи по ссылке он мог бы выбросить NullPointerException, как показано ниже:

третья иллюстрация

Надеюсь, это поможет.

Автор: Ganesh Размещён: 17.10.2013 07:54

80 плюса

6626 Репутация автора

В Java все ссылки, поэтому, когда у вас есть что-то вроде: Point pnt1 = new Point(0,0);Java делает следующее:

  1. Создает новый объект Point
  2. Создает новую ссылку Point и инициализирует эту ссылку точкой (ссылкой) на ранее созданный объект Point.
  3. Отсюда, через жизнь объекта Point, вы получите доступ к этому объекту через ссылку pnt1. Таким образом, мы можем сказать, что в Java вы манипулируете объектом через его ссылку.

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

Java не передает аргументы метода по ссылке; он передает их по значению. Я буду использовать пример с этого сайта :

public static void tricky(Point arg1, Point arg2) {
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args) {
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X1: " + pnt1.x + " Y1:" + pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);  
}

Ход программы:

Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);

Создание двух разных объектов Point с двумя разными ссылками. введите описание изображения здесь

System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
System.out.println(" ");

Ожидаемый результат будет:

X1: 0     Y1: 0
X2: 0     Y2: 0

В этой строке «передача по значению» входит в игру ...

tricky(pnt1,pnt2);           public void tricky(Point arg1, Point arg2);

Список литература pnt1и pnt2которые передаются по значению к хитрому способу, что означает , что теперь ваши ссылки pnt1и pnt2имеют их copiesимени arg1и arg2.so pnt1и arg1 точки на тот же объект. (То же самое для pnt2и arg2) введите описание изображения здесь

В trickyметоде:

 arg1.x = 100;
 arg1.y = 100;

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

Далее в trickyметоде

Point temp = arg1;
arg1 = arg2;
arg2 = temp;

Here, you first create new temp Point reference which will point on same place like arg1 reference. Then you move reference arg1 to point to the same place like arg2 reference. Finally arg2 will point to the same place like temp.

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

From here scope of tricky method is gone and you don't have access any more to the references: arg1, arg2, temp. But important note is that everything you do with these references when they are 'in life' will permanently affect object on which they are point to.

So after executing method tricky, when you return to main, you have this situation: введите описание изображения здесь

So now, completely execution of program will be:

X1: 0         Y1: 0
X2: 0         Y2: 0
X1: 100       Y1: 100
X2: 0         Y2: 0
Автор: Srle Размещён: 21.11.2013 04:04

68 плюса

1822 Репутация автора

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

Getting an outside of the box view, let's look at Assembly or some low level memory management. At the CPU level a reference to anything immediately becomes a value if it gets written to memory or to one of the CPU registers. (That is why pointer is a good definition. It is a value, which has a purpose at the same time).

Data in memory has a Location and at that location there is a value (byte,word, whatever). In Assembly we have a convenient solution to give a Name to certain Location (aka variable), but when compiling the code, the assembler simply replaces Name with the designated location just like your browser replaces domain names with IP addresses.

Down to the core it is technically impossible to pass a reference to anything in any language without representing it (when it immediately becomes a value).

Lets say we have a variable Foo, its Location is at the 47th byte in memory and its Value is 5. We have another variable Ref2Foo which is at 223rd byte in memory, and its value will be 47. This Ref2Foo might be a technical variable, not explicitly created by the program. If you just look at 5 and 47 without any other information, you will see just two Values. If you use them as references then to reach to 5 we have to travel:

(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223]  -> 47
(Foo)[47]       -> 5

This is how jump-tables work.

If we want to call a method/function/procedure with Foo's value, there are a few possible way to pass the variable to the method, depending on the language and its several method invocation modes:

  1. 5 gets copied to one of the CPU registers (ie. EAX).
  2. 5 gets PUSHd to the stack.
  3. 47 gets copied to one of the CPU registers
  4. 47 PUSHd to the stack.
  5. 223 gets copied to one of the CPU registers.
  6. 223 gets PUSHd to the stack.

In every cases above a value - a copy of an existing value - has been created, it is now upto the receiving method to handle it. When you write "Foo" inside the method, it is either read out from EAX, or automatically dereferenced, or double dereferenced, the process depends on how the language works and/or what the type of Foo dictates. This is hidden from the developer until she circumvents the dereferencing process. So a reference is a value when represented, because a reference is a value that has to be processed (at language level).

Now we have passed Foo to the method:

  • in case 1. and 2. if you change Foo (Foo = 9) it only affects local scope as you have a copy of the Value. From inside the method we cannot even determine where in memory the original Foo was located.
  • in case 3. and 4. if you use default language constructs and change Foo (Foo = 11), it could change Foo globally (depends on the language, ie. Java or like Pascal's procedure findMin(x, y, z: integer;var m: integer);). However if the language allows you to circumvent the dereference process, you can change 47, say to 49. At that point Foo seems to have been changed if you read it, because you have changed the local pointer to it. And if you were to modify this Foo inside the method (Foo = 12) you will probably FUBAR the execution of the program (aka. segfault) because you will write to a different memory than expected, you can even modify an area that is destined to hold executable program and writing to it will modify running code (Foo is now not at 47). BUT Foo's value of 47 did not change globally, only the one inside the method, because 47 was also a copy to the method.
  • in case 5. and 6. if you modify 223 inside the method it creates the same mayhem as in 3. or 4. (a pointer, pointing to a now bad value, that is again used as a pointer) but this is still a local problem, as 223 was copied. However if you are able to dereference Ref2Foo (that is 223), reach to and modify the pointed value 47, say, to 49, it will affect Foo globally, because in this case the methods got a copy of 223 but the referenced 47 exists only once, and changing that to 49 will lead every Ref2Foo double-dereferencing to a wrong value.

Nitpicking on insignificant details, even languages that do pass-by-reference will pass values to functions, but those functions know that they have to use it for dereferencing purposes. This pass-the-reference-as-value is just hidden from the programmer because it is practically useless and the terminology is only pass-by-reference.

Strict pass-by-value is also useless, it would mean that a 100 Mbyte array should have to be copied every time we call a method with the array as argument, therefore Java cannot be stricly pass-by-value. Every language would pass a reference to this huge array (as a value) and either employs copy-on-write mechanism if that array can be changed locally inside the method or allows the method (as Java does) to modify the array globally (from the caller's view) and a few languages allows to modify the Value of the reference itself.

So in short and in Java's own terminology, Java is pass-by-value where value can be: either a real value or a value that is a representation of a reference.

Автор: karatedog Размещён: 13.12.2013 12:23

46 плюса

221884 Репутация автора

I thought I'd contribute this answer to add more details from the Specifications.

First, What's the difference between passing by reference vs. passing by value?

Passing by reference means the called functions' parameter will be the same as the callers' passed argument (not the value, but the identity - the variable itself).

Pass by value means the called functions' parameter will be a copy of the callers' passed argument.

Or from wikipedia, on the subject of pass-by-reference

In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value. This typically means that the function can modify (i.e. assign to) the variable used as argument—something that will be seen by its caller.

And on the subject of pass-by-value

In call-by-value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function [...]. If the function or procedure is able to assign values to its parameters, only its local copy is assigned [...].

Second, we need to know what Java uses in its method invocations. The Java Language Specification states

When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables, each of the declared type, before execution of the body of the method or constructor.

So it assigns (or binds) the value of the argument to the corresponding parameter variable.

What is the value of the argument?

Let's consider reference types, the Java Virtual Machine Specification states

There are three kinds of reference types: class types, array types, and interface types. Their values are references to dynamically created class instances, arrays, or class instances or arrays that implement interfaces, respectively.

The Java Language Specification also states

The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object.

The value of an argument (of some reference type) is a pointer to an object. Note that a variable, an invocation of a method with a reference type return type, and an instance creation expression (new ...) all resolve to a reference type value.

So

public void method (String param) {}
...
String var = new String("ref");
method(var);
method(var.toString());
method(new String("ref"));

all bind the value of a reference to a String instance to the method's newly created parameter, param. This is exactly what the definition of pass-by-value describes. As such, Java is pass-by-value.

The fact that you can follow the reference to invoke a method or access a field of the referenced object is completely irrelevant to the conversation. The definition of pass-by-reference was

This typically means that the function can modify (i.e. assign to) the variable used as argument—something that will be seen by its caller.

In Java, modifying the variable means reassigning it. In Java, if you reassigned the variable within the method, it would go unnoticed to the caller. Modifying the object referenced by the variable is a different concept entirely.


Primitive values are also defined in the Java Virtual Machine Specification, here. The value of the type is the corresponding integral or floating point value, encoded appropriately (8, 16, 32, 64, etc. bits).

Автор: Sotirios Delimanolis Размещён: 03.07.2014 06:48

50 плюса

5715 Репутация автора

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

/ **

Передать по значению

В Java все параметры передаются по значению, т. Е. Назначение аргумента метода не отображается вызывающей стороне.

* /

Пример 1:

public class PassByValueString {
    public static void main(String[] args) {
        new PassByValueString().caller();
    }

    public void caller() {
        String value = "Nikhil";
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

Результат

output : output
value : Nikhil
valueflag : false

Пример 2:

/ ** * * Передать по значению * * /

public class PassByValueNewString {
    public static void main(String[] args) {
        new PassByValueNewString().caller();
    }

    public void caller() {
        String value = new String("Nikhil");
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

Результат

output : output
value : Nikhil
valueflag : false

Пример 3:

/ ** Это «Pass By Value» имеет ощущение «Pass By Reference»

Некоторые люди говорят, что примитивные типы и «String» - это «передача по значению», а объекты - «передача по ссылке».

Но из этого примера мы можем понять, что это только передача по значению, имея в виду, что здесь мы передаем ссылку как значение. т.е. ссылка передается по значению. Вот почему могут измениться, и все же это справедливо после локальной области. Но мы не можем изменить фактическую ссылку за пределы исходной области. что это означает, продемонстрировано на следующем примере PassByValueObjectCase2.

* /

public class PassByValueObjectCase1 {

    private class Student {
        int id;
        String name;
        public Student() {
        }
        public Student(int id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student [id=" + id + ", name=" + name + "]";
        }
    }

    public static void main(String[] args) {
        new PassByValueObjectCase1().caller();
    }

    public void caller() {
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student);
    }

    public String method(Student student) {
        student.setName("Anand");
        return "output";
    }
}

Результат

output : output
student : Student [id=10, name=Anand]

Пример 4:

/ **

В дополнение к тому, что было упомянуто в примере 3 (PassByValueObjectCase1.java), мы не можем изменить фактическую ссылку за пределы исходной области. "

Примечание. Я не вставляю код для private class Student. Определение класса для Studentтакое же, как в примере 3.

* /

public class PassByValueObjectCase2 {

    public static void main(String[] args) {
        new PassByValueObjectCase2().caller();
    }

    public void caller() {
        // student has the actual reference to a Student object created
        // can we change this actual reference outside the local scope? Let's see
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student); // Will it print Nikhil or Anand?
    }

    public String method(Student student) {
        student = new Student(20, "Anand");
        return "output";
    }

}

Результат

output : output
student : Student [id=10, name=Nikhil]
Автор: spiderman Размещён: 12.05.2015 09:24

35 плюса

1398 Репутация автора

В Java только ссылки передаются и передаются по значению:

Все аргументы Java передаются по значению (ссылка используется при использовании метода):

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

В случае объектов это тоже самое: переменные объекта - это указатели (сегменты), содержащие только адрес объекта, который был создан с использованием ключевого слова «new», и копируются как примитивные типы.

Поведение может отличаться от примитивных типов: поскольку скопированная переменная объекта содержит один и тот же адрес (для одного и того же объекта). Содержимое / члены объекта все еще могут быть изменены внутри метода, а затем и доступ снаружи, создавая иллюзию, что сам (содержащий) объект был передан по ссылке.

«Строковые» объекты кажутся идеальным контрпримером к городской легенде о том, что «объекты передаются по ссылке»:

По сути, внутри метода вы никогда не сможете обновить значение строки, переданной в качестве аргумента:

String Object, содержит символы в массиве, объявленном как final, который нельзя изменить. Только адрес объекта может быть заменен другим, используя «новый». Использование «new» для обновления переменной не позволит получить доступ к объекту извне, поскольку переменная изначально была передана по значению и скопирована.

Автор: user1767316 Размещён: 24.07.2016 08:29

59 плюса

161 Репутация автора

Java is a call by value

How it works

  • You always pass a copy of the bits of the value of the reference!

  • If it's a primitive data type these bits contain the value of the primitive data type itself, That's why if we change the value of header inside the method then it does not reflect the changes outside.

  • If it's an object data type like Foo foo=new Foo() then in this case copy of the address of the object passes like file shortcut , suppose we have a text file abc.txt at C:\desktop and suppose we make shortcut of the same file and put this inside C:\desktop\abc-shortcut so when you access the file from C:\desktop\abc.txt and write 'Stack Overflow' and close the file and again you open the file from shortcut then you write ' is the largest online community for programmers to learn' then total file change will be 'Stack Overflow is the largest online community for programmers to learn' which means it doesn't matter from where you open the file , each time we were accessing the same file , here we can assume Foo as a file and suppose foo stored at 123hd7h(original address like C:\desktop\abc.txt ) address and 234jdid(copied address like C:\desktop\abc-shortcut which actually contains the original address of the file inside) .. So for better understanding make shortcut file and feel.

Автор: Himanshu arora Размещён: 08.04.2017 05:51

36 плюса

978 Репутация автора

There are already great answers that cover this. I wanted to make a small contribution by sharing a very simple example (which will compile) contrasting the behaviors between Pass-by-reference in c++ and Pass-by-value in Java.

A few points:

  1. The term "reference" is a overloaded with two separate meanings. In Java it simply means a pointer, but in the context of "Pass-by-reference" it means a handle to the original variable which was passed in.
  2. Java is Pass-by-value, but allows us to emulate pass be reference by passing a Java reference (i.e. a pointer) by value. Meaning it passes a copy of the Java reference. EDIT: since someone made a comment about this, let me explain. Before C, several (but not all) earlier languages like FORTRAN and COBOL supported PBR, but C did not. In order to change the values of variables inside functions, C programmers emulated PBR by passing pointers to variables into functions. Languages inspired by C, such as Java, borrowed this idea and continue to emulate PBR as C did.
  3. C++ allows Pass-by-reference by declaring a reference parameter using the "&" character (which happens to be the same character used to indicate "the address of a variable" in both C and C++). For example, if we pass in a pointer by reference, the parameter and the argument are not just pointing to the same object. Rather, they are the same variable. If one gets set to a different address or to null, so does the other.
  4. In the C++ example below I'm passing a pointer to a null terminated string by reference. And in the Java example below I'm passing a Java reference to a String (again, the same as a pointer to a String) by value. Notice the output in the comments.

C++ pass by reference example:

using namespace std;
#include <iostream>

void change (char *&str){   // the '&' makes this a reference parameter
    str = NULL;
}

int main()
{
    char *str = "not Null";
    change(str);
    cout<<"str is " << str;      // ==>str is <null>
}

Java pass "a Java reference" by value example

public class ValueDemo{

    public void change (String str){
        str = null;
    }

     public static void main(String []args){
        ValueDemo vd = new ValueDemo();
        String str = "not null";
        vd.change(str);
        System.out.println("str is " + str);    // ==> str is not null!!
                                                // Note that if "str" was
                                                // passed-by-reference, it
                                                // WOULD BE NULL after the
                                                // call to change().
     }
}

EDIT

Several people have written comments which seem to indicate that either they are not looking at my examples or they don't get the c++ example. Not sure where the disconnect is, but guessing the c++ example is not clear. I'm posting the same example in pascal because I think pass-by-reference looks cleaner in pascal, but I could be wrong. I might just be confusing people more; I hope not.

In pascal, parameters passed-by-reference are called "var parameters". In the procedure setToNil below, please note the keyword 'var' which precedes the parameter 'ptr'. When a pointer is passed to this procedure, it will be passed by reference. Note the behavior: when this procedure sets ptr to nil (that's pascal speak for NULL), it will set the argument to nil--you can't do that in Java.

program passByRefDemo;
type 
   iptr = ^integer;
var
   ptr: iptr;

   procedure setToNil(var ptr : iptr);
   begin
       ptr := nil;
   end;

begin
   new(ptr);
   ptr^ := 10;
   setToNil(ptr);
   if (ptr = nil) then
       writeln('ptr seems to be nil');     { ptr should be nil, so this line will run. }
end.

EDIT 2

Some excerpts from "THE Java Programming Language" by Ken Arnold, James Gosling (the guy who invented Java), and David Holmes, chapter 2, section 2.6.5

All parameters to methods are passed "by value". In other words, values of parameter variables in a method are copies of the invoker specified as arguments.

He goes on to make the same point regarding objects . . .

You should note that when the parameter is an object reference, it is the object reference-not the object itself-that is passed "by value".

And towards the end of the same section he makes a broader statement about java being only pass by value and never pass by reference.

The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing mode-pass by value-and that helps keep things simple.

This section of the book has a great explanation of parameter passing in Java and of the distinction between pass-by-reference and pass-by-value and it's by the creator of Java. I would encourage anyone to read it, especially if you're still not convinced.

I think the difference between the two models is very subtle and unless you've done programming where you actually used pass-by-reference, it's easy to miss where two models differ.

I hope this settles the debate, but probably won't.

EDIT 3

I might be a little obsessed with this post. Probably because I feel that the makers of Java inadvertently spread misinformation. If instead of using the word "reference" for pointers they had used something else, say dingleberry, there would've been no problem. You could say, "Java passes dingleberries by value and not by reference", and nobody would be confused. (Hence forth, when referencing pass by reference vs value, I shall refer to references as dinglebarries.)

That's the reason only Java developers have issue with this. They look at the word "reference" and think they know exactly what that means, so they don't even bother to consider the opposing argument.

Anyway, I noticed a comment by dhackner in an older post, who made a balloon analogy which I really liked. So much so that I decided to glue together some clip-art to make a set of cartoons to illustrate the point.

Passing a reference by value--Changes to the reference are not reflected in the caller's scope, but the changes to the object are. This is because the reference is copied, but the both the original and the copy refer to the same object. Передача ссылок на объекты по значению

Pass by reference--There is no copy of the reference. Single reference is shared by both the caller and the function being called. Any changes to the reference or the Object's data are reflected in the caller's scope. Передать по ссылке

EDIT 4

I have seen posts on this topic which describe the low level implementation of parameter passing in Java, which I think is great and very helpful because it makes an abstract idea concrete. However, to me the question is more about the behavior described in the language specification than about the technical implementation of the behavior. This is an exerpt from the Java Language Specification, section 8.4.1 :

When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables, each of the declared type, before execution of the body of the method or constructor. The Identifier that appears in the DeclaratorId may be used as a simple name in the body of the method or constructor to refer to the formal parameter.

Which means, java creates a copy of the passed parameters before executing a method. Like most people who took compilers in college I used "The Dragon Book" which is THE compilers book. It has a good description of "Call-by-value" and "Call-by-Reference" in Chapter 1. The Call-by-value description matches up with Java Specs exactly.

When I took compilers, I used the first edition of the book from 1986 which pre-dated Java by about 9 or 10 years. However, I just ran across a copy of the 2nd Eddition from 2007 which actually mentions Java! Section 1.6.6 labeled "Parameter Passing Mechanisms" describes parameter passing pretty nicely. Here is an excerpt under the heading "Call-by-value" which mentions Java:

In call-by-value, the actual parameter is evaluated (if it is an expression) or copied (if it is a variable). The value is placed in the location belonging to the corresponding formal parameter of the called procedure. This method is used in C and Java, and is a common option in C++ , as well as in most other languages.

Автор: Sanjeev Размещён: 25.01.2019 09:37
Вопросы из категории :
32x32