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

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

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

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

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


person Community    schedule 02.09.2008    source источник
comment
Мы бы чаще говорили, что переменная, передаваемая по ссылке, может быть изменена. Этот термин появляется в учебниках, потому что теоретикам языка нужен был способ отличить, как вы относитесь к примитивным типам данных (int, bool, byte) от сложных и структурированных объектов (массив, потоки, класс), то есть объекты с возможно неограниченной памятью. распределение.   -  person jlau    schedule 04.08.2020
comment
Хочу отметить, что в большинстве случаев об этом не нужно думать. Я программировал java много лет, пока не изучил C ++. До этого момента я понятия не имел, что такое передача по ссылке и передача по значению. У меня всегда работало интуитивно понятное решение, поэтому java - один из лучших языков для начинающих. Так что, если вы в настоящее время беспокоитесь, если вашей функции нужна ссылка или значение, просто передайте его как есть, и все будет в порядке.   -  person Tobias    schedule 20.10.2020
comment
Java передает ссылку по значению.   -  person The Student    schedule 20.10.2020
comment
Короче говоря, эта путаница возникает из-за того, что в Java все непримитивные типы данных обрабатываются / доступны через ссылки. Однако передача всегда имеет значение. Таким образом, для всех непримитивных типов ссылка передается по его значению. Все примитивные типы также передаются по значению.   -  person Ozair Kafray    schedule 10.11.2020
comment
Для тех, кто приходит с C++ и начинает путаться при прикосновении к Java, это может помочь как ярлык.   -  person jack    schedule 27.12.2020
comment
Я нашел это весьма полезным: baeldung.com/java- передать по значению или по ссылке   -  person Natasha Kurian    schedule 20.01.2021
comment
В этом разница между foo.bar (sth) и foo = sth. В первом случае объект изменяется с использованием переменной, указывающей на него, и сама переменная, указывающая на объект, не была изменена. Однако во втором случае сама переменная, которая раньше указывала на объект, изменилась и теперь указывает на другой объект. Если у вас есть опыт работы на C ++: указатель - это переменная, которая содержит адрес памяти, а ссылка имеет тот же адрес памяти, что и элемент, на который она ссылается. На самом деле в Java указатель передается по значению, но Javaist'ы называют его ссылкой!   -  person aderchox    schedule 28.02.2021
comment
Что в таком случае будет означать для некоторого языка передать ссылку не по значению? Передача указателей на указатели? Есть ли такие языки? Разве языки, такие как C / C ++, также не передают ссылки и указатели по значению ??   -  person hippietrail    schedule 03.06.2021


Ответы (89)


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() в 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.

person Community    schedule 02.09.2008
comment
так что же происходит с Фифи в 1-м примере? Он перестает существовать, никогда не создавался или существует в куче, но без ссылочной переменной в стеке? - person dbrewster; 29.09.2020
comment
Что вы имеете в виду под последним предложением but it is not possible to change the value of the variable aDog itself.? - person TMOTTM; 16.10.2020
comment
Для меня сказать, что ссылка на объект передается по значению, то же самое, что сказать, что объект передается по ссылке. Я новичок в Java, но предполагаю, что (напротив) примитивные данные передаются по значению. - person user36800; 27.10.2020
comment
@ user36800: Вы ошибаетесь. Вы проработали пример с Фифи и внимательно просмотрели результаты? Убедитесь, что действительно foo(aDog); не изменился aDog, несмотря на foo перезапись значения d, показывая, что действительно все входные данные функции передаются по значению. - person user21820; 23.12.2020
comment
@ user21820: Да, я проработал примеры, и оба они мне понятны. В своем предыдущем комментарии я сделал два заявления. Если вы можете указать, с чем вы не согласны, я могу попытаться лучше понять ваш последний комментарий. Спасибо. - person user36800; 28.12.2020
comment
@ user36800: Что ж, оба утверждения неверны. Передача объекта по ссылке будет означать, что если функция изменяет переменную, то она изменяет сам объект. Это не то, что происходит в Java; объекты не могут передаваться по ссылке, но вместо этого можно передавать только ссылки в качестве входных данных в функцию, и когда функция выполняет d = new Dog("Fifi");, она перезаписывает входную переменную d, которая хранит ссылку, но не является объектом передан по ссылке ». Сравните с &d в сигнатуре функции в C, которая будет передаваться по ссылке. [продолжение] - person user21820; 28.12.2020
comment
Это было ваше первое заявление. Ваше второе утверждение также неверно, потому что все передается по значению в Java. Нет абсолютно никакой разницы между ссылками на объекты и примитивными типами данных, за исключением того, что операции, которые вам разрешено выполнять с ними, различаются. - person user21820; 28.12.2020
comment
Ах я вижу. Спасибо, что разъяснили это. Я просто подумал грубо, то есть приравнять передачу по ссылке к отсутствию создания нового объекта, потому что указатели используются за кулисами, а указатели автоматически разыменовываются при использовании переменной. Было бы намного понятнее, если бы указатели использовались явно. Однако положение о том, что все объекты Java обрабатываются по ссылке, помогает. - person user36800; 29.12.2020
comment
Java передается по значению, НО В противном случае существует ВРЕМЕННОЕ РЕШЕНИЕ. Использование массива, содержащего ссылку на объект. Несмотря на то, что массив передается как значение, поэтому, если вы измените массив, он не будет отражаться. Но массив содержит ссылку на объект Integer. ПОПРОБУЙТЕ ЭТО: - {Целое число [] i = новое целое число [] {новое целое число (0)}; System.out.println (я [0]); я [0] = я [0] +1; System.out.println (я [0]); изменить (я); System.out.println (я [0]); } общедоступное статическое изменение недействительности (целое число [] я) {я [0] = я [0] +1; } - person Prateek Pande; 13.01.2021
comment
@dbrewster извини, но ... Фифи больше нет среди нас - person ghilesZ; 02.02.2021
comment
Так в чем же тогда разница между ссылкой на объект и значением ссылки на объект. - person redd77; 30.04.2021
comment
@ redd77, когда вы передаете значение, вы не передаете фактическую переменную, а только то значение, которое она содержит. Это означает, что вы делаете копию значений и передаете копию. Ссылка на объект (то есть указатель) - это переменная, содержащая физический адрес памяти, в которой находится объект. Значения ссылки на объект - это копия этого адреса. Языки, поддерживающие передачу по ссылке, позволяют передавать фактическую переменную, а не только копию, так что изменение ее в функции (например, установка значения null) также изменяет ее для вызывающего. - person Sanjeev; 09.06.2021
comment
@ redd77 Единственное отличие состоит в том, что присвоение значению ссылки на объект не затрагивает объект. В этом смысле он похож на указатель C / C ++. - person Matt F.; 22.06.2021

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

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

Ключ к пониманию этого в том, что что-то вроде

Dog myDog;

не собака; на самом деле это указатель на Dog. Использование термина «ссылка» в Java вводит в заблуждение и вызывает здесь большую часть путаницы. То, что они называют ссылками, больше похоже на то, что мы называем указателями в большинстве других языков.

Это значит, что у вас есть

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
  • at line "AAA"
    • someDog is followed to the Dog it points to (the Dog object at address 42)
    • что Dog (тот, что по адресу 42) попросили изменить его имя на Макс
  • at line "BBB"
    • a new Dog is created. Let's say he's at address 74
    • присваиваем параметру someDog значение 74
  • at line "CCC"
    • someDog is followed to the Dog it points to (the Dog object at address 74)
    • этот Dog (тот, что находится по адресу 74) попросили изменить его имя на Rowlf
  • затем мы возвращаемся

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

Изменилось ли myDog?

Вот и ключ.

Учитывая, что myDog является указателем, а не реальным Dog, ответ - НЕТ. myDog по-прежнему имеет значение 42; он по-прежнему указывает на исходный Dog (но обратите внимание, что из-за строки AAA его имя теперь Max - все тот же Dog; значение myDog не изменилось.)

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

Java работает точно так же, как C. Вы можете назначить указатель, передать указатель на метод, следовать за указателем в методе и изменить данные, на которые он указывал. Однако вызывающий не увидит никаких изменений, которые вы вносите в то место, куда указывает этот указатель. (На языке с семантикой передачи по ссылке функция метода может изменить указатель, и вызывающий объект увидит это изменение.)

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

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

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

person Community    schedule 16.09.2008
comment
Незначительный уточняющий вопрос по приведенному выше примеру, так что при создании нового Dog в BBB по адресу 72, подразумевается ли это после возврата созданного Dog по адресу 72, и его значение теряется и возвращается к 42? - person ebresie; 13.03.2021
comment
@ebresie javarevisited.blogspot.com/2015/09/. - person Ravikumar; 15.03.2021
comment
@ebresie В основном да (я проясню это чуть позже). Единственный указатель на новую собаку на 74 (я полагаю, вы имели в виду 74, а не 72) - это параметр функции foo. Когда foo возвращается, все его параметры извлекаются из стека, поэтому ничего не остается, указывающее на 72, и его можно собрать сборщиком мусора. Я говорю в основном потому, что возврата не происходит; указатель myDog в вызывающей программе все время указывал на 42 и никогда не менялся, что бы ни происходило в функции, следовательно, возврата не было. - person Scott Stanchfield; 16.03.2021
comment
Однако вы не можете изменить место, куда указывает этот указатель. - ›Не должно быть. Однако вы не можете изменить положение этого указателя каким-либо другим методом. - person NiharGht; 08.06.2021
comment
@NiharGht Хороший момент - я разъяснил его (прокомментируйте еще раз, если все еще не ясно) - person Scott Stanchfield; 10.06.2021
comment
Java не действует точно так же, как C. Если вы передаете указатель на функцию в C и изменяете место, на которое указывает этот указатель, эффект переназначения этого указателя будет виден в поле зрения вызова, а не только в рамках вызова. Поиск такого поведения в языках - это цель ключевого слова const. Пожалуйста, перестаньте говорить, что java похожа на C, потому что во многих основных отношениях она полностью НЕ c (или c ++), и все, что вы делаете, это сбивает с толку людей, которые действительно знают C (или C ++) и пытаются получить рабочий обзор java. . См .: course.washington.edu/css342/zander/css332/passby.html < / а> - person Jonathan; 24.06.2021
comment
@Jonathan Эта ссылка - C ++, а не C. C так не работает. C строго передается по значению, как и Java. Если вы передадите указатель на что-либо, указатель будет значением, за которым вы можете следовать. Вы не можете изменить указатель, но можете следовать за ним и изменять значение, на которое он указывает. Если перенаправить его, вызывающий не увидит изменения. В C ++ вы можете передать ссылку на что-то (на той странице, на которую вы ссылаетесь как на int &), что похоже на псевдоним; если вы измените его в функции / методе, он фактически изменит объект / примитив / указатель, переданный в качестве аргумента. - person Scott Stanchfield; 26.06.2021

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 работает передача объектов в качестве аргументов :)

person Community    schedule 14.09.2012
comment
Java всегда передает аргументы по значению, но то, что вы передаете по значению, является ссылкой на объект, а не его копией. Просто а? - person dan carter; 07.12.2020
comment
Я надеюсь, что книга Герберта Шильдта, по которой я изучал Java, научила этому - person Harsha; 27.03.2021

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

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

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

  • Студент: Магистр, означает ли это, что Java передается по ссылке?
  • Мастер: Grasshopper, No.

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

  1. Переменная содержит биты, которые сообщают JVM, как добраться до указанного объекта в памяти (куче).
  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, и в начале она пуста.
  • Новый объект Person создается в строке № 2, сохраняется в памяти, а переменной person дается ссылка на объект Person. То есть его адрес. Допустим, 3bad086a.
  • Переменная person, содержащая адрес объекта, передается функции в строке №3.
  • В строке №4 можно послушать звук тишины.
  • Проверьте комментарий в строке №5
  • A method local variable -anotherReferenceToTheSamePersonObject- is created and then comes the magic in line #6:
    • The variable/reference person is copied bit-by-bit and passed to anotherReferenceToTheSamePersonObject inside the function.
    • Новые экземпляры Person не создаются.
    • И "person", и "anotherReferenceToTheSamePersonObject" содержат одинаковое значение 3bad086a.
    • Не пытайтесь это сделать, но person == anotherReferenceToTheSamePersonObject будет истинным.
    • Обе переменные имеют ОДИНАКОВЫЕ КОПИИ ссылки, и обе они относятся к одному и тому же объекту Person, ОДНОМУ объекту в куче, а НЕ КОПИИ.

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

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

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

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

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

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

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

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


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


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

person Community    schedule 12.08.2011
comment
Я пробовал это: ‹br /› File file = new File (C: /); changeFile (файл); System.out.println (file.getAbsolutePath ()); } общедоступный статический void changeFile (файл f) {f = новый файл (D: /); } ` - person Excessstone; 29.06.2021

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

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

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

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

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

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

person Community    schedule 02.09.2008
comment
JVMS 2.2 проясняет это: существует ... два типа значений, которые могут храниться в переменных, передаваться в качестве аргументов, возвращаться методами и обрабатываться: примитивные значения и ссылочные значения . Ссылки на объекты - это значения. Все передается по стоимости. - person Brian Goetz; 01.11.2020
comment

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

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

person Community    schedule 02.09.2008

Мне кажется, что споры о передаче по ссылке и передаче по значению бесполезны.

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

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

Хорошо. Во-первых, в стек попадают локальные примитивы. Итак, этот код:

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

приводит к этому:

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

Когда вы объявляете и создаете экземпляр объекта. Фактический объект попадает в кучу. Что идет в стек? Адрес объекта в куче. Программисты на C ++ назвали бы это указателем, но некоторые разработчики Java выступают против слова «указатель». Что бы ни. Просто знайте, что адрес объекта идет в стек.

Вот так:

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

a b * 7ch aint one!

Массив - это объект, поэтому он тоже попадает в кучу. А как насчет объектов в массиве? У них есть собственное пространство кучи, и адрес каждого объекта входит в массив.

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

братья маркс

Итак, что передается, когда вы вызываете метод? Если вы передаете объект, вы фактически передаете его адрес. Кто-то может сказать «значение» адреса, а кто-то скажет, что это просто ссылка на объект. Так зародилась священная война между сторонниками «ссылки» и «ценности». Не так важно то, что вы называете им, просто то, что вы понимаете, что передается адрес объекта.

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, которому назначается адрес уже существующей String.

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

Итак, значение, ссылка? Вы говорите «картофель».

person Community    schedule 11.09.2013
comment
Такой потрясающий ответ, который мог понять даже такой дурак, как я. Я бы добавил также, что передача по значению буквально означает, что передается буквальное значение в стеке. - person Dude156; 13.09.2020

Чтобы показать контраст, сравните следующие 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 есть только два типа передачи: по значению для встроенных типов и по значению указателя для типов объектов.

person Community    schedule 17.09.2008
comment
Это показывает, что java не передается по значению, поскольку он не копирует весь объект в стек, как это делает C ++, как показано в примере выше - ..., Dog obj, ... - person Solubris; 26.11.2020
comment
Нет, Java передает ссылки по значению. Вот почему, когда вы перезаписываете objPtr в примере с java, исходный объект Dog не изменяется. Но если изменить объект, на который указывает objPtr, это произойдет. - person Eclipse; 27.11.2020

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

person Community    schedule 02.09.2008
comment
Пожалуйста, кто-нибудь проголосуйте против этого ответа, так как он не содержит никаких объяснений и неприятен копией ответа от других! У меня недостаточно репутации, чтобы отклонить этот бесполезный ответ. - person Diana; 13.05.2021

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

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.

person Community    schedule 02.09.2008

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

person Community    schedule 07.09.2010

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

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

person Community    schedule 12.01.2009

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

  1. Создает новый объект Point
  2. Создает новую ссылку на точку и инициализирует эту ссылку на точку (ссылка) на ранее созданном объекте 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, поэтому pnt1 и arg1 точки для тот же объект. (То же самое для pnt2 и arg2) введите описание изображения здесь

В методе tricky:

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

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

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

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

Здесь вы сначала создаете новую temp точку привязки, которая будет указывать на то же место, что и ссылка arg1. Затем вы перемещаете ссылку arg1 в точку в то же место, что и ссылка arg2. Наконец, arg2 укажет на то же место, что и temp.

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

Отсюда область применения метода tricky исчезла, и у вас больше нет доступа к ссылкам: arg1, arg2, temp. Но важно отметить, что все, что вы делаете с этими ссылками, когда они «в жизни», навсегда повлияет на объект, на который они указывают.

Итак, после выполнения метода tricky, когда вы вернетесь к main, у вас будет такая ситуация: введите описание изображения здесь

Итак, теперь полное выполнение программы будет:

X1: 0         Y1: 0
X2: 0         Y2: 0
X1: 100       Y1: 100
X2: 0         Y2: 0
person Community    schedule 21.11.2013

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, как показано ниже:

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

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

person Community    schedule 17.10.2013

На это уже есть отличные ответы. Я хотел внести небольшой вклад, поделившись очень простым примером (который будет компилироваться), противопоставляющим поведение между передачей по ссылке в C ++ и передачей по значению в Java.

Несколько моментов:

  1. Термин «ссылка» имеет два разных значения. В Java это просто означает указатель, но в контексте «Передача по ссылке» это означает дескриптор исходной переменной, которая была передана.
  2. Java - это передача по значению. Java является потомком C (среди других языков). До C некоторые (но не все) более ранние языки, такие как FORTRAN и COBOL, поддерживали PBR, а C - нет. PBR позволял этим другим языкам вносить изменения в переданные переменные внутри подпрограмм. Чтобы выполнить то же самое (т.е. изменить значения переменных внутри функций), программисты на C передали указатели на переменные в функции. Языки, вдохновленные C, такие как Java, позаимствовали эту идею и продолжают передавать указатели на методы, как это делал C, за исключением того, что Java вызывает свои указатели References. Опять же, это другое использование слова «Ссылка», чем в «Передача по ссылке».
  3. C ++ допускает передачу по ссылке, объявляя параметр ссылки с помощью символа «&» (который является тем же символом, который используется для обозначения «адреса переменной» как в C, так и в C ++). Например, если мы передаем указатель по ссылке, параметр и аргумент не просто указывают на один и тот же объект. Скорее, это одна и та же переменная. Если один получает другой адрес или значение null, то же самое происходит и с другим.
  4. В приведенном ниже примере C ++ я передаю указатель на строку с завершающим нулем по ссылке. А в приведенном ниже примере Java я передаю ссылку Java на String (опять же, как указатель на String) по значению. Обратите внимание на результат в комментариях.

Пример передачи C ++ по ссылке:

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 передает "ссылку на Java" по примеру значения

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().
     }
}

ИЗМЕНИТЬ

Несколько человек написали комментарии, которые, кажется, указывают на то, что либо они не смотрят мои примеры, либо они не понимают пример C ++. Не уверен, где происходит отключение, но угадать пример С ++ неясно. Я публикую тот же пример на паскале, потому что я думаю, что передача по ссылке выглядит чище на паскале, но я могу ошибаться. Я мог бы просто больше сбивать людей с толку; Надеюсь нет.

В паскале параметры, передаваемые по ссылке, называются "параметрами var". В приведенной ниже процедуре setToNil обратите внимание на ключевое слово var, которое предшествует параметру ptr. Когда в эту процедуру передается указатель, он будет передан по ссылке. Обратите внимание на поведение: когда эта процедура устанавливает для ptr значение nil (это паскаль означает NULL), она устанавливает для аргумента значение nil - вы не можете этого сделать в 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.

ИЗМЕНИТЬ 2

Некоторые отрывки из "ЯЗЫКА ПРОГРАММИРОВАНИЯ Java" Кена Арнольда, Джеймса Гослинга (изобретателя Java) и Дэвида Холмса, глава 2, раздел 2.6.5

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

Он продолжает делать то же самое в отношении объектов. . .

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

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

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

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

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

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

ИЗМЕНИТЬ 3

Я мог бы быть немного одержим этим постом. Наверное, потому, что я чувствую, что создатели Java непреднамеренно распространяют дезинформацию. Если бы вместо слова «ссылка» для указателей они использовали что-то другое, скажем, dingleberry, проблем не было бы. Вы можете сказать: «Java передает dingleberries по значению, а не по ссылке», и никого не смущает.

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

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

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

Передать по ссылке: копия ссылки отсутствует. Единая ссылка используется как вызывающим, так и вызываемой функцией. Любые изменения ссылки или данных объекта отражаются в области действия вызывающего объекта. Передать по ссылке

ИЗМЕНИТЬ 4

Я видел сообщения по этой теме, в которых описывается низкоуровневая реализация передачи параметров в Java, что, на мой взгляд, здорово и очень полезно, потому что оно конкретизирует абстрактную идею. Однако для меня вопрос больше о поведении, описанном в спецификации языка, чем о технической реализации поведения. Это отрывок из Java Спецификация языка, раздел 8.4.1:

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

Это означает, что java создает копию переданных параметров перед выполнением метода. Как и большинство людей, изучавших компиляторы в колледже, я использовал "Книгу дракона" ", которая является THE книгой для компиляторов. Он имеет хорошее описание «Вызов по значению» и «Вызов по ссылке» в главе 1. Описание Вызов по значению точно соответствует спецификациям Java.

Когда я изучал компиляторы - в 90-х, я использовал первое издание книги 1986 года, которое предшествовало Java примерно на 9 или 10 лет. Однако я только что наткнулся на копию 2-го издания из 2007 , где фактически упоминается Java! Раздел 1.6.6, озаглавленный «Механизмы передачи параметров», довольно хорошо описывает передачу параметров. Вот отрывок под заголовком «Вызов по значению», в котором упоминается Java:

При вызове по значению фактический параметр оценивается (если это выражение) или копируется (если это переменная). Значение размещается в месте, принадлежащем соответствующему формальному параметру вызываемой процедуры. Этот метод используется в C и Java и является распространенным вариантом в C ++, а также в большинстве других языков.

person Community    schedule 25.01.2019

Java - это передача по значению (стековая память)

Как это работает

  • Давайте сначала поймем, где java хранит примитивный тип данных и тип данных объекта.

  • Сами примитивные типы данных и ссылки на объекты хранятся в стеке. Сами объекты хранятся в куче.

  • Это означает, что в стековой памяти хранятся примитивные типы данных, а также адреса объектов.

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

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

  • Если это тип данных объекта, например Foo foo = new Foo (), то в этом случае копия адреса объекта передается как ярлык файла, предположим, что у нас есть текстовый файл abc.txt < / strong> в C: \ desktop и предположим, что мы создаем ярлык того же файла и помещаем его в C: \ desktop \ abc-shortcut, чтобы при доступе к файлу из C: \ desktop \ abc.txt и напишите «переполнение стека», закройте файл и снова вы открываете файл с помощью ярлыка, затем вы пишете '- самый большой онлайн-сообщество для обучения программистов », тогда общее изменение файла будет равно « Stack Overflow - это крупнейшее онлайн-сообщество для обучения программистов », что означает, что не имеет значения, откуда вы открываете файл. , каждый раз, когда мы обращались к одному и тому же файлу, здесь мы можем принять Foo как файл и предположить, что foo хранится по адресу 123hd7h (исходный адрес, например C: \ desktop \ abc.txt) адрес s и 234jdid (скопированный адрес, например C: \ desktop \ abc-shortcut, который фактически содержит исходный адрес файла внутри) .. Так что для лучшего понимания создайте файл ярлыка и Чувствовать.

person Community    schedule 08.04.2017
comment
Молодец, ты был ясно дал понять. - person SangLe; 28.04.2021

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

Чтобы получить нестандартное представление, давайте посмотрим на сборку или какое-нибудь управление памятью на низком уровне. На уровне ЦП ссылка на что-либо немедленно становится значением, если оно записывается в память или в один из регистров ЦП. (Вот почему указатель - хорошее определение. Это значение, которое в то же время имеет цель).

Данные в памяти имеют Местоположение, и в этом месте есть значение (байт, слово и т. Д.). В Ассемблере у нас есть удобное решение присвоить Имя определенному Местоположение (также известному как переменная), но при компиляции кода ассемблер просто заменяет Имя с указанным местоположением, точно так же, как ваш браузер заменяет доменные имена на IP-адреса.

В глубине души технически невозможно передать ссылку на что-либо на любом языке без ее представления (когда она сразу становится значением).

Допустим, у нас есть переменная Foo, ее Расположение находится в 47-м байте памяти, а ее Значение равно 5. У нас есть еще одна переменная Ref2Foo, которая занимает 223-й байт в памяти, и его значение будет 47. Ref2Foo может быть технической переменной, явно не созданной программой. Если вы просто посмотрите на 5 и 47 без какой-либо другой информации, вы увидите только два значения. Если вы используете их как ссылки, то, чтобы добраться до 5, нам нужно проехать:

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

Вот как работают прыжковые столы.

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

  1. 5 копируется в один из регистров ЦП (т.е. EAX).
  2. 5 получает PUSHd в стек.
  3. 47 копируется в один из регистров процессора.
  4. 47 PUSHd в стек.
  5. 223 копируется в один из регистров ЦП.
  6. 223 помещает PUSHd в стек.

Во всех случаях, когда значение выше - копия существующего значения - было создано, теперь метод получения должен обработать его. Когда вы пишете "Foo" внутри метода, он либо считывается из EAX, либо автоматически разыменован, либо дважды разыменован, процесс зависит от того, как работает язык и / или от того, что диктует тип Foo. . Это скрыто от разработчика, пока он не обойдет процесс разыменования. Таким образом, ссылка - это значение при представлении, потому что ссылка - это значение, которое необходимо обработать (на уровне языка).

Теперь мы передали Foo методу:

  • в случае 1. и 2. если вы измените Foo (Foo = 9), это повлияет только на локальную область, поскольку у вас есть копия значения. Изнутри метода мы даже не можем определить, где в памяти находился исходный Foo.
  • в случае 3. и 4. если вы используете языковые конструкции по умолчанию и изменяете Foo (Foo = 11), это может изменить Foo глобально (в зависимости от языка, например, Java или типа procedure findMin(x, y, z: integer; var m : integer); Паскаля). Однако, если язык позволяет обойти процесс разыменования, вы можете изменить 47, скажем, на 49. В этот момент кажется, что Foo был изменен, если вы его читали, потому что вы изменили на него локальный указатель. И если вы измените этот Foo внутри метода (Foo = 12), вы, вероятно, FUBAR выполните программу (также известную как segfault), потому что вы будете писать в другую память, чем ожидалось, вы даже можете изменить область, предназначенную для хранения исполняемая программа и запись в нее изменят работающий код (Foo теперь не на 47). НО значение 47 в Foo не изменилось глобально, только внутри метода, потому что 47 также был копией метода.
  • в случаях 5. и 6. если вы измените 223 внутри метода, это создаст тот же хаос, что и в случае 3. или 4. (указатель, указывающий на теперь уже плохое значение, которое снова используется как указатель), но это все еще локальная проблема, так как 223 был скопирован. Однако, если вы можете разыменовать Ref2Foo (то есть 223), достичь и изменить указанное значение 47, скажем, на 49, это повлияет на Foo глобально, потому что в этом случае методы получили копию of 223, но указанный 47 существует только один раз, и изменение его на 49 приведет к каждому Ref2Foo двойному разыменованию на неправильное значение.

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

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

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

person Community    schedule 13.12.2013

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

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, потому что в функции подкачки вы используете копии, которые не влияют на ссылки в файле main. Но если ваши объекты не являются неизменяемыми, вы можете изменить это, например:

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

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

person Community    schedule 01.04.2009

Нет, не по ссылке.

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

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

person Community    schedule 12.10.2012

Позвольте мне попытаться объяснить свое понимание с помощью четырех примеров. 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:

/ ** Эта передача по значению имеет ощущение передачи по ссылке

Некоторые люди говорят, что примитивные типы и 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 такое же, как в Example3.

*/

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]
person Community    schedule 12.05.2015

Вы никогда не можете передавать по ссылке в Java, и один из очевидных способов - это когда вы хотите вернуть более одного значения из вызова метода. Рассмотрим следующий фрагмент кода на 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;
}

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

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

Как объяснялось в предыдущих ответах, в Java вы передаете указатель на массив как значение в getValues. Этого достаточно, потому что затем метод изменяет элемент массива, и по соглашению вы ожидаете, что элемент 0 будет содержать возвращаемое значение. Очевидно, вы можете сделать это другими способами, например, структурировать код, чтобы в этом не было необходимости, или создать класс, который может содержать возвращаемое значение или позволять его устанавливать. Но простой шаблон, доступный вам в C ++ выше, недоступен в Java.

person Community    schedule 08.03.2009

Я подумал, что внесу этот ответ, чтобы добавить больше деталей из спецификаций.

Во-первых, В чем разница между передачей по ссылке и . передача по значению?

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

Передача по значению означает, что параметр вызываемой функции будет копией переданного аргумента вызывающей стороны.

Или из Википедии, о передаче по ссылке

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

И о передаче по значению

При вызове по значению вычисляется выражение аргумента, и результирующее значение связывается с соответствующей переменной в функции [...]. Если функция или процедура может присваивать значения своим параметрам, назначается только ее локальная копия [...].

Во-вторых, нам нужно знать, что Java использует при вызовах своих методов. Спецификация языка Java государства

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

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

Каково значение аргумента?

Давайте рассмотрим ссылочные типы, виртуальную машину Java. В спецификации говорится

Существует три типа ссылочных типов: типы классов, типы массивов и типы интерфейсов. Их значения являются ссылками на динамически создаваемые экземпляры классов, массивы или экземпляры или массивы классов, реализующие интерфейсы, соответственно.

Спецификация языка Java также заявляет

Справочные значения (часто просто ссылки) являются указателями на эти объекты и специальной пустой ссылкой, которая не ссылается ни на какой объект.

Значение аргумента (некоторого ссылочного типа) является указателем на объект. Обратите внимание, что переменная, вызов метода с возвращаемым типом ссылочного типа и выражение создания экземпляра (new ...) разрешаются в значение ссылочного типа.

So

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

все привязывают значение ссылки к экземпляру String к вновь созданному параметру метода param. Это именно то, что описывает определение передачи по значению. Таким образом, Java передается по значению.

Тот факт, что вы можете следовать ссылке, чтобы вызвать метод или получить доступ к полю объекта, на который указывает ссылка, совершенно не имеет отношения к беседе. Определение передачи по ссылке было

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

В Java изменение переменной означает ее переназначение. В Java, если вы переназначаете переменную в методе, это останется незамеченным для вызывающего. Изменение объекта, на который ссылается переменная, - это совершенно другая концепция.


Примитивные значения также определены в спецификации виртуальной машины Java, здесь. Значение типа представляет собой соответствующее целое значение или значение с плавающей запятой, закодированное соответствующим образом (8, 16, 32, 64 и т. Д. Бит).

person Community    schedule 03.07.2014

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

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

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

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

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

Объекты типа "String" кажутся хорошим контрпримером городской легенде о том, что "объекты передаются по ссылке":

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

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

person Community    schedule 24.07.2016

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

person Community    schedule 03.09.2008

Как многие люди упоминали ранее, 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;
  }
}

Печать:

До: a = 2, b = 3
После: a = 2, b = 3

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

person Community    schedule 03.09.2008

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

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:

name = Maxx
name = Fido

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

person Community    schedule 08.09.2008

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

Когда метод изменяет параметр примитивного типа, изменения параметра не влияют на исходное значение аргумента в вызывающем методе.

Что касается объектов, сами объекты нельзя передать методам. Итак, мы передаем ссылку (адрес) объекта. Мы можем управлять исходным объектом, используя эту ссылку.

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

Account account1 = new Account();

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

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

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

На изображении ниже вы можете видеть, что у нас есть две ссылочные переменные (они называются указателями в C / C ++, и я думаю, что этот термин упрощает понимание этой функции.) В основном методе. Примитивные и ссылочные переменные хранятся в стековой памяти (слева на изображениях ниже). Ссылочные переменные array1 и array2 "точка" (как это называют программисты C / C ++) или ссылка на массивы a и b соответственно, которые являются объектами (значения, которые содержат эти ссылочные переменные, являются адресами объектов) в памяти кучи (правая сторона на изображениях ниже) .

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

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

public class Test
{
    public static void reverseArray(int[] array1)
    {
        // ...
    }

    public static void main(String[] args)
    {
        int[] array1 = { 1, 10, -7 };
        int[] array2 = { 5, -190, 0 };

        reverseArray(array1);
    }
}

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

Итак, если мы скажем

array1[0] = 5;

в методе reverseArray он внесет изменение в массив a.

У нас есть еще одна ссылочная переменная в методе reverseArray (array2), которая указывает на массив c. Если бы мы сказали

array1 = array2;

в методе reverseArray ссылочная переменная array1 в методе reverseArray перестанет указывать на массив a и начнет указывать на массив c (пунктирная линия на втором изображении).

Если мы вернем значение ссылочной переменной array2 в качестве возвращаемого значения метода reverseArray и присвоим это значение ссылочной переменной array1 в основном методе, array1 в main начнет указывать на массив c.

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

public class Test
{
    public static int[] reverseArray(int[] array1)
    {
        int[] array2 = { -7, 0, -1 };

        array1[0] = 5; // array a becomes 5, 10, -7

        array1 = array2; /* array1 of reverseArray starts
          pointing to c instead of a (not shown in image below) */
        return array2;
    }

    public static void main(String[] args)
    {
        int[] array1 = { 1, 10, -7 };
        int[] array2 = { 5, -190, 0 };

        array1 = reverseArray(array1); /* array1 of 
         main starts pointing to c instead of a */
    }
}

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

И теперь, когда метод reverseArray завершен, его ссылочные переменные (array1 и array2) исчезли. Это означает, что теперь у нас есть только две ссылочные переменные в основном методе array1 и array2, которые указывают на массивы c и b соответственно. Никакая ссылочная переменная не указывает на объект (массив) a. Таким образом, он имеет право на сборку мусора.

Вы также можете присвоить значение array2 в основном array1. array1 начнет указывать на b.

person Community    schedule 03.04.2018

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();
}
person Community    schedule 10.07.2013

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

Также упоминается Java. Вот краткое изложение:

  • Java передает ему параметры по значению
  • "по значению" - единственный способ в java передать параметр методу.
  • использование методов из объекта, указанного в качестве параметра, изменит объект, поскольку ссылки указывают на исходные объекты. (если сам метод изменяет некоторые значения)
person Community    schedule 08.09.2008

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

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

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

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

person Community    schedule 02.09.2008
comment
Это просто неправильно. То, что Java вызывает ссылку, C ++ вызывает указатель. То, что C ++ вызывает ссылку, не существует в Java. Ссылка C ++ - это указатель, подобный типу, но с глобальной областью видимости. Когда вы изменяете ссылку C ++, все вхождения этих ссылок изменяются как в вызываемой функции, так и в вызывающей функции. Java не может этого сделать. Java строго передается по значению, и изменения в ссылках на Java строго локальны. Вызываемая функция Java не может изменить ссылочное значение вызывающей функции. Вы можете эмулировать ссылку C ++, используя объекты-оболочки, такие как AtomicReference. - person Talijanac; 18.08.2020
comment
Ссылки C ++ не имеют ничего общего с областями действия. В реализации они похожи на указатели, которым не разрешено иметь нулевые значения. Основное отличие заключается в том, что синтаксически они действуют как псевдонимы данных, на которые имеются ссылки. В Java ссылки работают почти так же, но имеют специальные правила, которые позволяют: сравнение с нулевым значением и другими ссылочными значениями (с использованием оператора ==). C ++ также передается по значению, хотя это значение может быть указателем / ссылкой на ссылку. - person Paul de Vrieze; 15.09.2020
comment
Изменения в ссылках C ++, сделанные вызываемым методом, также видны вызывающим методом. Этого не существует в Java, и это не указатель, как поведение. В Java и C изменения значений указателя являются только локальными. Я не знаю, как правильно вызвать такое поведение, но оно чем-то похоже на внешнюю область действия некоторых языков сценариев. - person Talijanac; 16.09.2020
comment
Пример правильной передачи по ссылке см. В программе обмена здесь: geeksforgeeks.org/references-in -c Невозможно написать метод подкачки на Java с такими же побочными эффектами. Есть качество (поведение операторов языка) для ссылок C ++, которого нет в ссылках Java или указателях C. - person Talijanac; 16.09.2020

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

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

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

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

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

person Community    schedule 26.12.2009

Java передает параметры по VALUE и по значению ONLY.

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

Для тех, кто использует C #: НЕТ параметра out.

Для тех, кто приходит с PASCAL: НЕТ параметра var.

Это означает, что вы не можете изменить ссылку из самого объекта, но вы всегда можете изменить свойства объекта.

Обходной путь - использовать параметр StringBuilder вместо String. И вы всегда можете использовать массивы!

person Community    schedule 18.03.2015

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

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

Передача по значению: значения параметров метода копируются в другую переменную, а затем передается скопированный объект, поэтому он называется передачей по значению.

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

Допустим, у нас есть воздушный шар класса, как показано ниже.

public class Balloon {

    private String color;

    public Balloon(){}

    public Balloon(String c){
        this.color=c;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

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

public class Test {

    public static void main(String[] args) {

        Balloon red = new Balloon("Red"); //memory reference 50
        Balloon blue = new Balloon("Blue"); //memory reference 100

        swap(red, blue);
        System.out.println("red color="+red.getColor());
        System.out.println("blue color="+blue.getColor());

        foo(blue);
        System.out.println("blue color="+blue.getColor());

    }

    private static void foo(Balloon balloon) { //baloon=100
        balloon.setColor("Red"); //baloon=100
        balloon = new Balloon("Green"); //baloon=200
        balloon.setColor("Blue"); //baloon = 200
    }

    //Generic swap method
    public static void swap(Object o1, Object o2){
        Object temp = o1;
        o1=o2;
        o2=temp;
    }
}

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

red color=Red
blue color=Blue
blue color=Red

Если вы посмотрите на первые две строки вывода, станет ясно, что метод подкачки не сработал. Это связано с тем, что Java передается по значению, этот тест метода swap () можно использовать с любым языком программирования, чтобы проверить, передается ли он по значению или по ссылке.

Пошагово разберем выполнение программы.

Balloon red = new Balloon("Red");
Balloon blue = new Balloon("Blue");

Когда мы используем оператор new для создания экземпляра класса, создается экземпляр, а переменная содержит ссылку на ячейку памяти, в которой сохраняется объект. В нашем примере предположим, что «красный» указывает на 50, а «синий» указывает на 100, и это место в памяти обоих объектов Balloon.

Теперь, когда мы вызываем метод swap (), создаются две новые переменные o1 и o2, указывающие на 50 и 100 соответственно.

Итак, нижеприведенный фрагмент кода объясняет, что произошло при выполнении метода swap ().

public static void swap(Object o1, Object o2){ //o1=50, o2=100
    Object temp = o1; //temp=50, o1=50, o2=100
    o1=o2; //temp=50, o1=100, o2=100
    o2=temp; //temp=50, o1=100, o2=50
} //method terminated

Обратите внимание, что мы изменяем значения o1 и o2, но они являются копиями «красных» и «синих» опорных точек, поэтому на самом деле нет никаких изменений в значениях «красный» и «синий» и, следовательно, в выходных данных.

Если вы дошли до этого момента, вы легко поймете причину путаницы. Поскольку переменные - это всего лишь ссылка на объекты, мы не понимаем, что мы передаем ссылку, поэтому Java передается по ссылке. Однако мы передаем копию ссылки и, следовательно, передаем ее по значению. Надеюсь, теперь это рассеивает все сомнения.

Теперь давайте проанализируем выполнение метода foo ().

private static void foo(Balloon balloon) { //baloon=100
    balloon.setColor("Red"); //baloon=100
    balloon = new Balloon("Green"); //baloon=200
    balloon.setColor("Blue"); //baloon = 200
}

Первая строка является важной, когда мы вызываем метод, который вызывается для объекта в указанном месте. В этот момент воздушный шар указывает на 100 и, следовательно, его цвет меняется на красный.

В следующей строке ссылка на баллон изменяется на 200, и любые дальнейшие выполняемые методы применяются к объекту в ячейке памяти 200 и не оказывают никакого влияния на объект в ячейке памяти 100. Это объясняет третью строку вывода нашей программы, печатающую синий цвет. = Красный.

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

person Community    schedule 06.09.2017

Это лучший способ ответить на вопрос imo ...

Во-первых, мы должны понять, что в Java поведение при передаче параметров ...

public void foo(Object param)
{
  // some code in foo...
}

public void bar()
{
  Object obj = new Object();

  foo(obj);
}

точно так же, как ...

public void bar()
{
  Object obj = new Object();

  Object param = obj;

  // some code in foo...
}

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

Фактически, в Java мы ищем то, как работает присвоение переменных. Я нашел его в документах:

Один из наиболее распространенных операторов, с которыми вы столкнетесь, - это простой оператор присваивания "=" [...] он присваивает значение справа операнду слева:

int cadence = 0;
int speed = 0;
int gear = 1;

Этот оператор также можно использовать для объектов, чтобы назначать ссылки на объекты [...]

Понятно, что этот оператор действует двумя разными способами: присваивает значения и присваивает ссылки. Последнее, когда это объект ... первое, когда это не объект, то есть примитив. Но так, можем ли мы понять, что параметры функции Java могут быть передачей по значению и передачей по ссылке?

Правда в коде. Давай попробуем:

public class AssignmentEvaluation
{
  static public class MyInteger
  {
    public int value = 0;
  }

  static public void main(String[] args)
  {
    System.out.println("Assignment operator evaluation using two MyInteger objects named height and width\n");

    MyInteger height = new MyInteger();
    MyInteger width  = new MyInteger();

    System.out.println("[1] Assign distinct integers to height and width values");

    height.value = 9;
    width.value  = 1;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are different things! \n");

    System.out.println("[2] Assign to height's value the width's value");

    height.value = width.value;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");

    System.out.println("[3] Assign to height's value an integer other than width's value");

    height.value = 9;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are different things yet! \n");

    System.out.println("[4] Assign to height the width object");

    height = width;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");

    System.out.println("[5] Assign to height's value an integer other than width's value");

    height.value = 9;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are the same thing now! \n");

    System.out.println("[6] Assign to height a new MyInteger and an integer other than width's value");

    height = new MyInteger();
    height.value = 1;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are different things again! \n");
  }
}

Это результат моего прогона:

Assignment operator evaluation using two MyInteger objects named height and width

[1] Assign distinct integers to height and width values
->  height is 9 and width is 1, we are different things! 

[2] Assign to height's value the width's value
->  height is 1 and width is 1, are we the same thing now? 

[3] Assign to height's value an integer other than width's value
->  height is 9 and width is 1, we are different things yet! 

[4] Assign to height the width object
->  height is 1 and width is 1, are we the same thing now? 

[5] Assign to height's value an integer other than width's value
->  height is 9 and width is 9, we are the same thing now! 

[6] Assign to height a new MyInteger and an integer other than width's value
->  height is 1 and width is 9, we are different things again! 

В [2] у нас есть отдельные объекты, и мы присваиваем значение одной переменной другой. Но после присвоения нового значения в [3] объекты имели разные значения, что означает, что в [2] присвоенное значение было копией примитивной переменной, обычно называемой передача по значению, в противном случае значения, напечатанные в [3], должны быть такими же.

В [4] у нас все еще есть отдельные объекты, и мы назначаем один объект другому. И после присвоения нового значения в [5] объекты имели те же значения, что означает, что в [4] назначенный объект не был копией другого, что следует называть передачей по ссылке. Но, если мы внимательно посмотрим на [6], мы не можем быть уверены, что копия не была сделана ... ?????

Мы не можем быть в этом уверены, потому что в [6] объекты были одинаковыми, затем мы назначили новый объект одному из них, и после этого объекты имели разные значения! Как они могли бы отличаться друг от друга, если бы были такими же? Они и здесь должны быть такими же! ?????

Чтобы понять, что происходит, нам нужно помнить документы. :

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

Итак, две наши переменные хранили ссылки ... наши переменные имели одну и ту же ссылку после [4] и разные ссылки после [6] ... если такое возможно , это означает, что присвоение объектов выполняется копией ссылки на объект, в противном случае, если это не копия ссылки, напечатанное значение переменных в [6] должно быть таким же. Таким образом, объекты (ссылки), как и примитивы, копируются в переменные посредством присваивания, что люди обычно называют передачей по значению. Это единственный проходный в Java.

person Community    schedule 02.02.2018

Java копирует ссылку по значению. Поэтому, если вы измените его на что-то другое (например, используя new), ссылка не изменится вне метода. Для собственных типов он всегда передается по значению.

person Community    schedule 26.12.2009

Это действительно довольно просто:

Для переменной примитивного типа (например, int, boolean, char и т. Д.), Когда вы используете ее имя в качестве аргумента метода, вы передаете содержащееся в нем значение (5, true или 'c'). Это значение «копируется», и переменная сохраняет свое значение даже после вызова метода.

Для переменной ссылочного типа (например, String, Object и т. Д.), Когда вы используете ее имя в качестве аргумента метода, вы передаете содержащееся в нем значение (ссылочное значение который «указывает» на объект). Это ссылочное значение «копируется», и переменная сохраняет свое значение даже после вызова метода. Ссылочная переменная продолжает «указывать» на один и тот же объект.

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


Сравните это, чтобы сказать C ++, где у вас может быть метод для получения int&, или в C #, где вы могли бы взять ref int (хотя в этом случае вы также должны использовать модификатор ref при передаче имени переменной методу. )

person Community    schedule 01.08.2012

Во всех ответах мы видим, что Java-передача по значению или, скорее, как написал @Gevorg: «передача-по-копии-значения-переменной», и это идея, которую мы должны иметь в виду все время.

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

Из [1] В Java аргументы всегда передаются по копии; то есть вы всегда создаете новый экземпляр значения внутри функции. Но есть определенные варианты поведения, которые могут заставить вас думать, что вы переходите по ссылке.

  • Передача по копии: когда переменная передается методу / функции, создается копия (иногда мы слышим, что, передавая примитивы, вы делаете копии).

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

Примеры передачи по копии / по значению

Пример из [ref 1]

void incrementValue(int inFunction){
  inFunction ++;
  System.out.println("In function: " + inFunction);
}

int original = 10;
System.out.print("Original before: " + original);
incrementValue(original);
System.out.println("Original after: " + original);

We see in the console:
 > Original before: 10
 > In Function: 11
 > Original after: 10 (NO CHANGE)

Пример из [ref 2]

прекрасно показывает механизм смотреть максимум 5 минут

(Передача по ссылке) передача по копии значения переменной

Пример из [ref 1] (помните, что массив - это объект)

void incrementValu(int[] inFuncion){
  inFunction[0]++;
  System.out.println("In Function: " + inFunction[0]);
}

int[] arOriginal = {10, 20, 30};
System.out.println("Original before: " + arOriginal[0]);
incrementValue(arOriginal[]);
System.out.println("Original before: " + arOriginal[0]);

We see in the console:
  >Original before: 10
  >In Function: 11
  >Original before: 11 (CHANGE)

Сами сложные объекты копируются, но внутренние ссылки сохраняются.

Пример из [ref 3]

package com.pritesh.programs;

class Rectangle {
  int length;
  int width;

  Rectangle(int l, int b) {
    length = l;
    width = b;
  }

  void area(Rectangle r1) {
    int areaOfRectangle = r1.length * r1.width;
    System.out.println("Area of Rectangle : " 
                            + areaOfRectangle);
  }
}

class RectangleDemo {
  public static void main(String args[]) {
    Rectangle r1 = new Rectangle(10, 20);
    r1.area(r1);
  }
}

Площадь прямоугольника 200, длина = 10 и ширина = 20.

Последнее, чем я хотел бы поделиться, это момент лекции: Распределение памяти, которое я нашел очень полезным в понимании передачи Java по значению или, скорее, «передача-копией-значения-переменной», как написал @Gevorg.

  1. REF 1 Lynda.com
  2. REF 2 Professor Mehran Sahami
  3. REF 3 c4learn
person Community    schedule 25.09.2014

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

person Community    schedule 31.12.2012
comment
В Java не существует такой вещи, как «постоянная ссылка», если только программист не укажет «finally». - person user207421; 02.08.2013
comment
Под постоянной ссылкой я имел в виду, что невозможно изменить саму ссылку, сказав new MyClass () в функции. Если я правильно выразился, ссылки на объекты передаются по значению, что означает, что передается копия ссылки, поэтому вы можете изменить данные, на которые ссылается эта ссылка, но вы не можете изменить их с помощью нового оператора и выделить новый объект. - person fatma.ekici; 09.09.2013
comment
Так что исправь свой ответ. Если бы это была константа, вы не могли бы переназначить ее внутри вызываемого метода, и можете, если вы не укажете final. - person user207421; 25.09.2014

Так много длинных ответов. Позвольте мне дать простой пример:

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

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

person Community    schedule 16.03.2016

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

Рассмотрим следующие 3 ситуации:

1) Попытка изменить примитивную переменную

public static void increment(int x) { x++; }

int a = 3;
increment(a);

x скопирует значение a и будет увеличивать x, значение a останется прежним

2) Попытка изменить примитивное поле объекта

public static void increment(Person p) { p.age++; }

Person pers = new Person(20); // age = 20
increment(pers);

p скопирует ссылочное значение pers и увеличит поле возраста, переменные ссылаются на один и тот же объект, поэтому возраст будет изменен

3) Попытка изменить эталонное значение эталонных переменных

public static void swap(Person p1, Person p2) {
    Person temp = p1;
    p1 = p2;
    p2 = temp;
}

Person pers1 = new Person(10);
Person pers2 = new Person(20);
swap(pers1, pers2);

после вызова swap p1, p2 копирует ссылочные значения из pers1 и pers2, меняются местами со значениями, поэтому pers1 и pers2 остаются такими же

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

person Community    schedule 21.01.2016

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

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

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

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

@Test
public void sampleTest(){
    int i = 5;
    incrementBy100(i);
    System.out.println("passed ==> "+ i);
    Integer j = new Integer(5);
    incrementBy100(j);
    System.out.println("passed ==> "+ j);
}
/**
 * @param i
 */
private void incrementBy100(int i) {
    i += 100;
    System.out.println("incremented = "+ i);
}

Результат:

incremented = 105
passed ==> 5
incremented = 105
passed ==> 5

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

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

@Test
public void sampleTest2(){
    Person person = new Person(24, "John");
    System.out.println(person);
    alterPerson(person);
    System.out.println(person);
}

/**
 * @param person
 */
private void alterPerson(Person person) {
    person.setAge(45);
    Person altered = person;
    altered.setName("Tom");
}

private static class Person{
    private int age;
    private String name; 

    public Person(int age, String name) {
        this.age=age;
        this.name =name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Person [age=");
        builder.append(age);
        builder.append(", name=");
        builder.append(name);
        builder.append("]");
        return builder.toString();
    }

}

В этом случае на выходе получается:

Person [age=24, name=John]
Person [age=45, name=Tom]
person Community    schedule 30.12.2016

Java передается строго по значению

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

Важным моментом было бы знать, что даже язык C строго передается только по значению:
т.е.: данные копируются от вызывающего к вызываемому, и, более того, операции, выполняемые вызываемым, выполняются на одно и то же место в памяти и то, что мы им передаем, является адресом этого места, которое мы получаем из оператора (&), а идентификатор, используемый в формальных параметрах, объявлен как переменная-указатель (*), с помощью которой мы можем попасть внутрь области памяти для доступ к данным в нем.

Следовательно, здесь формальный параметр - не что иное, как псевдонимы для этого местоположения. И любые изменения, сделанные в этом месте, видны везде, где активна эта область переменной (которая идентифицирует это местоположение).

В Java нет концепции указателей (т.е. нет ничего, что называется переменной-указателем), хотя мы можем рассматривать ссылочную переменную как указатель, технически в java мы называем ее дескриптором. Причина, по которой мы вызываем указатель на адрес как дескриптор в java, заключается в том, что переменная-указатель может выполнять не только одно разыменование, но и множественное разыменование, например: int *p; в P означает, что p указывает на целое число, а int **p; в C означает, что p равно указатель на указатель на целое число, у нас нет этого средства в Java, поэтому его абсолютно правильно и технически законно называть его дескриптором, также есть правила для арифметики указателей в C., что позволяет выполнять арифметические операции с указателями с ограничениями на него .

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

(и если мы передаем данные непосредственно в C, мы называем это передачей по значению.)

В java, когда мы делаем то же самое, мы делаем это с помощью ручек; поскольку они не называются переменными-указателями, как в (как обсуждалось выше), даже если мы передаем ссылки, мы не можем сказать, что они передаются по ссылке, поскольку мы не собираем это с помощью переменной-указателя в Java.

Следовательно, Java строго использует механизм передачи по значению

person Community    schedule 22.10.2017

Важнейшее краеугольное знание должно быть цитируемым,

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

Java: Руководство для начинающих, шестое издание, Герберт Шильдт

person Community    schedule 14.11.2016

Взгляните на этот код. Этот код не будет генерировать _1 _... Он напечатает "Vinay"

public class Main {
    public static void main(String[] args) {
        String temp = "Vinay";
        print(temp);
        System.err.println(temp);
    }

    private static void print(String temp) {
        temp = null;
    }
}

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

person Community    schedule 09.08.2010

Я вижу, что все ответы содержат одно и то же: передать по значению. Однако недавнее сообщение Брайана Гетца о проекте Valhalla на самом деле отвечает на это иначе:

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

Вы можете прочитать больше здесь: Штат Валгалла. Раздел 2. Языковая модель

Изменить: Брайан Гетц - архитектор языка Java, возглавляющий такие проекты, как Project Valhalla и Project Amber.

Edit-2020-12-08: обновлено Штат Валгалла

person Community    schedule 09.02.2020
comment
Ссылки на объекты (то есть указатели) передаются по значению, а примитивы также передаются по значению. Это означает, что все всегда передается по значению. Я думаю, что здесь действует термин «передача по стоимости». - person Sanjeev; 21.02.2020
comment
Я думаю, что архитектор Java Language Architect, который возглавляет Project Amber и Project Valhalla, является надежным источником, утверждающим, что это не проходит по ценности. - person Mr.Robot; 02.04.2020
comment
Во-первых, я не думаю, что он более заслуживает доверия, чем Джеймс Гослинг, создатель Java, который четко заявляет в своей книге «Язык программирования Java», что Java действительно является передачей по значению (глава 2, раздел 2.6.5). Во-вторых, хотя Гетц говорит, что это не PBV и не PBR, он затем продолжает говорить, что ссылки ПРОХОДЯТ ПО ЗНАЧЕНИЮ, тем самым противореча самому себе. Если вы знаете Java, вы также знаете, что примитивы также проходят по значению. Поскольку все в Java передается по значению, Java является языком PASS BY VALUE. - person Sanjeev; 02.04.2020
comment
Другими источниками, заслуживающими большего доверия, чем Гетц, являются Ахо, Лам, Сетхи и Ульман, которые хорошо известны своей книгой «Компиляторы: принципы, методы и инструменты», стандартным учебником для колледжей по созданию компиляторов. В разделе 1.6.6 2-го издания этой книги также говорится, что Java является передачей по значению. - person Sanjeev; 02.04.2020
comment
И наиболее актуальной ссылкой является Спецификация языка Java, в которой говорится: Эффект от этого заключается в присвоении значений аргументов соответствующим недавно созданным переменным параметров метода. (15.12.4.5). Обратите внимание, что он избегает терминологической путаницы, вообще не говоря «пройти мимо ...». (FWIW, я не согласен с характеристикой Гетца передачи по значению и передачи ссылок по значению как семантически различных. И я согласен с тем, что он противоречит сам себе.) - person Stephen C; 05.04.2020
comment
Это единственный ответ, который до сих пор имел смысл. Объекты не передаются как чистые значения, потому что они не копируются, как при передаче по значению в C ++. - person AFP_555; 17.11.2020

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

Теперь люди любят бесконечно спорить о том, является ли «передача по ссылке» правильным способом описания того, что Java et al. на самом деле делаю. Дело вот в чем:

  1. Передача объекта не копирует объект.
  2. У объекта, переданного в функцию, могут быть изменены ее члены.
  3. Примитивное значение, переданное функции, не может быть изменено функцией. Сделана копия.

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

- Брайан Би - Какие языки программирования передаются по ссылке?

person Community    schedule 25.07.2018
comment
Я не уверен, что технически правильно упоминать, что копии делаются для примитивных типов. Примитивные типы неизменяемы, поэтому их нельзя изменить внутри метода, которому они передаются. Разница незначительна для таких вещей, как числа, но есть важное различие для потенциально больших строк. - person Dennis; 26.08.2018
comment
Этот ответ совершенно неверен и только создает путаницу. Java - это чистый язык передачи по значению. Что вас смущает, так это то, что значение может быть указателем на объект. Передача по ссылке означает, что можно будет изменить идентификатор объекта на стороне вызывающего. Например. присвоение нового объекта параметру метода также повлияет на указатель, который был передан в коде, вызывающем метод. - person Torben; 03.10.2018
comment
@Dennis Строки - это не примитивы, это объекты. - person nasch; 27.12.2018
comment
Дело не в том, что написано в вашей книге. Передача по ссылке и Передача по значению - это стандартные отраслевые термины, которые имеют очень конкретные определения. По этим определениям Java - это передача по значению без исключений. - person Sanjeev; 23.01.2019
comment
Передача объекта не является допустимой операцией в Java. Вы передаете ссылку на объект. Это не называется передачей по ссылке. Это называется передачей по значению. Переданная ссылка - это значение, которое копируется в новое место в стеке для использования методом, как и любое примитивное значение. - person AndrewF; 25.12.2019
comment
В C ++ есть настоящая передача по значению, при которой все поля объекта копируются в стек. Java этого не делает, поэтому его нельзя передавать по значению. - person Solubris; 26.11.2020
comment
Люди, знающие только Java, никогда не поймут, что передача по ссылке означает не что иное, как передачу ссылки (которая, по сути, является указателем) по значению. Который. конечно, это то, что делает JVM. - person Ingo; 01.12.2020

Короче:

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

Конец.

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

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

}

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

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


}
person Community    schedule 30.04.2019

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

Все аргументы передаются по значению.

Вызов метода может передавать два types of values методу

  • копии примитивных значений (например, значения типа int и double)
  • копии ссылок на объекты.

Objects themselves cannot be passed to methods. Когда метод изменяет параметр примитивного типа, изменения параметра не влияют на исходное значение аргумента в вызывающем методе.

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

Ссылки: Java ™ How To Program (Early Objects), Tenth Издание

person Community    schedule 30.03.2017

Простой тест для проверки того, поддерживает ли язык передачу по ссылке, - это просто написание традиционного свопа. Можете ли вы написать традиционный метод / функцию swap (a, b) на Java?

Традиционный метод или функция подкачки принимает два аргумента и меняет их местами, так что переменные, переданные в функцию, изменяются вне функции. Его основная структура выглядит как

(Не-Java) Базовая структура функции подкачки

swap(Type arg1, Type arg2) {
    Type temp = arg1;
    arg1 = arg2;
    arg2 = temp;
}

Если вы можете написать такой метод / функцию на своем языке, чтобы вызов

Type var1 = ...;
Type var2 = ...;
swap(var1,var2);

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

person Community    schedule 29.09.2016
comment
Возможно, вы захотите уточнить свое последнее предложение. Моя первая реакция на передачу только значений, а не указателей ... заключается в том, что ваша реализация Java, вероятно, делает именно это, передает указатель. Тот факт, что вы не можете разыменовать этот указатель, кажется несущественным. - person Loduwijk; 02.08.2017

  • передано по ссылке: вызывающий и вызываемый абоненты используют в качестве параметра одну и ту же переменную.

  • передается по значению: у вызывающего и вызываемого есть две независимые переменные с одинаковым значением.

  • Java uses pass by value
    • When passing primitive data, it copies the value of primitive data type.
    • При передаче объекта он копирует адрес объекта и передает переменную метода вызываемого объекта.

Пример использования примитивного типа данных:

public class PassByValuePrimitive {
    public static void main(String[] args) {
        int i=5;
        System.out.println(i);  //prints 5
        change(i);
        System.out.println(i);  //prints 5
    }


    private static void change(int i) {
        System.out.println(i);  //prints 5
        i=10;
        System.out.println(i); //prints 10

    }
}

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

public class PassByValueObject {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("prem");
        list.add("raj");
        new PassByValueObject().change(list);
        System.out.println(list); // prints [prem, raj, ram]

    }


    private  void change(List list) {
        System.out.println(list.get(0)); // prem
        list.add("ram");
        list=null;
        System.out.println(list.add("bheem")); //gets NullPointerException
    }
}
person Community    schedule 16.12.2017

Java передается по значению.

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

class Test    {

public static void main (String[] args) throws java.lang.Exception
{
    // Primitive type
    System.out.println("Primitve:");
    int a = 5;
    primitiveFunc(a);
    System.out.println("Three: " + a);    //5

    //Object
    System.out.println("Object:");
    DummyObject dummyObject = new DummyObject();
    System.out.println("One: " + dummyObject.getObj());    //555
    objectFunc(dummyObject);
    System.out.println("Four: " + dummyObject.getObj());    //666 (555 if line in method uncommented.)

}

private static void primitiveFunc(int b)    {
    System.out.println("One: " + b);    //5
    b = 10;
    System.out.println("Two:" + b);    //10
}

private static void objectFunc(DummyObject b)   {
    System.out.println("Two: " + b.getObj());    //555
    //b = new DummyObject();
    b.setObj(666);
    System.out.println("Three:" + b.getObj());    //666
}

}

class DummyObject   {
    private int obj = 555;
    public int getObj() { return obj; }
    public void setObj(int num) { obj = num; }
}

Если строка b = new DummyObject() раскомментирована, изменения, сделанные после этого, будут внесены в новый объект, новый экземпляр. Следовательно, это не отражается на месте, откуда вызывается метод. Однако в противном случае изменение отражается, поскольку изменения производятся только на «ссылке» объекта, то есть - b указывает на тот же dummyObject.

Иллюстрации в одном из ответов в этой теме (https://stackoverflow.com/a/12429953/4233180) могут помочь получить более глубокое понимание.

person Community    schedule 03.09.2017

PT 1: Объявления о недвижимости

На 1234 Main St сейчас припаркован синий Tiny House площадью 120 кв. Футов с ухоженным газоном и клумбой перед домом.

Нанимают риэлтора из местной фирмы, и ему велят вести список для этого дома.

Назовем этого Риэлтор Боб. Привет боб.

Боб постоянно обновляет свой Листинг, который он называет tinyHouseAt1234Main, с помощью веб-камеры, которая позволяет ему отмечать любые изменения в реальном доме в реальном времени. Он также ведет учет того, сколько людей спрашивали о листинге. Целое число Боба viewTally для дома сегодня составляет 42.

Когда кому-то нужна информация о синем Крошечном домике на Мейн-стрит, 1234, они спрашивают Боба.

Боб просматривает свой Листинг tinyHouseAt1234Main и рассказывает им все - цвет, красивый газон, кровать-чердак, компостный туалет и т. Д. Затем он добавляет их запрос к своему viewTally. Однако он не сообщает им настоящий физический адрес, потому что фирма Боба специализируется на крошечных домиках, которые можно переместить в любое время. Итого сейчас 43.

В другой фирме риэлторы могут прямо указать в своем листинге дом по адресу 1234 Main St, обозначив это небольшим * рядом с ним, потому что они в основном имеют дело с домами, которые редко когда-либо переезжают (хотя, по-видимому, для этого есть причины). Фирма Боба этим не занимается.

Теперь, конечно, Боб физически не идет и не ставит настоящий дом на грузовик, чтобы показать его клиентам напрямую - это было бы непрактично и нелепой тратой ресурсов. Передать полную копию его ведомости учета - одно дело, но постоянно обходить весь дом - дорого и нелепо.

(Кроме того: фирма Боба также не печатает на 3D-принтере новые и уникальные копии указанного дома каждый раз, когда кто-то спрашивает об этом. Это то, что делают выскочка, одноименная веб-фирма и ее дочерние компании - это дорого и медленнее, и люди часто путают две фирмы, но они все равно довольно популярны).

В некоторых других, более старых фирмах, расположенных ближе к морю, такого риэлтора, как Боб, может даже не существовать для управления листингами. Вместо этого клиенты могут проконсультироваться с Rolodex Annie (для краткости &), чтобы узнать прямой адрес дома. Вместо того, чтобы зачитывать данные о доме из списка, как это делает Боб, клиенты вместо этого получают адрес дома от Энни (&) и идут прямо на 1234 Main St, иногда не имея представления, что они могут там найти.

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

Что ж, человек с этой информацией - Боб, поэтому клиент просит Боба вызвать службу и отправить ей копию листинга.

jobKillingAutomatedListingService(Listing tinyHouseAt1234Main, int viewTally) Боб отправляет ...

Служба со своей стороны называет этот Листинг houseToLookAt, но на самом деле то, что он получает, является точной копией листинга Боба с точно такими же ЗНАЧЕНИЯМИ в нем, которые относятся к дому по адресу 1234 Main St.

Эта новая служба также имеет собственный внутренний подсчет количества людей, просмотревших объявление. Служба принимает подсчет Боба из профессиональной вежливости, но на самом деле это не заботит и все равно полностью перезаписывает его собственной локальной копией. Сегодняшний счет - 1, а Бобу все еще 43.

Агентства по продаже недвижимости называют это передачей по значению, поскольку Боб передает текущее значение своего viewTally и своего Листинга tinyHouseAt1234Main. На самом деле он не проходит через весь физический дом, потому что это непрактично. Он также не передает реальный физический адрес, как это сделала бы Энни (&).

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

ПТ II: Когда все становится запутанным и опасным ...

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

После получения объекта Listing, он позволяет клиентам фактически перекрасить НАСТОЯЩИЙ дом на 1234 Main St, используя удаленный флот роботов-дронов! Это позволяет клиентам управлять роботом-бульдозером, чтобы ДЕЙСТВИТЕЛЬНО выкопать клумбу! Это безумие!!!

Служба также позволяет клиентам полностью перенаправить houseToLookAt в другой дом по другому адресу, без участия Боба или его листинга. Внезапно они могли смотреть на улицу Вязов 4321, которая не имеет никакого отношения к списку Боба (к счастью, они больше не могут причинить ущерб).

Боб наблюдает за всем этим по своей веб-камере в реальном времени. Смирившись с тяжелой работой своей единственной должностной обязанности, он рассказывает клиентам о новой уродливой покраске и внезапном отсутствии обуздания. В конце концов, его листинг все еще находится на Мейн-стрит, 1234. Новая служба houseToLookAt не могла этого изменить. Боб сообщает подробности своего tinyHouseAt1234Main точно и послушно, как всегда, пока его не уволят или дом не будет полностью разрушен Ничто.

На самом деле единственное, что служба НЕ МОЖЕТ сделать со своей houseToLookAt копией исходного списка Боба, это изменить адрес с 1234 Main St. . Листинг Боба по-прежнему всегда указывает на 1234 Main St, чего бы он ни стоил. Он, как всегда, передает его текущее значение.

Этот странный побочный эффект передачи списка в новую автоматизированную службу сбивает с толку людей, которые спрашивают, как это работает. В самом деле, в чем разница между возможностью удаленного управления роботами, которые изменяют состояние дома на 1234 Main, и фактическим физическим посещением этого дома и сеансом хаоса из-за того, что Энни дала вам адрес ??

Похоже на своего рода придирчивый семантический аргумент, если вас обычно волнует состояние дома в листинге, который копируется и передается, верно?

Я имею в виду, если вы занимались тем, что собирали дома и физически перемещали их по другим адресам (не например, мобильные или крошечные дома, где это своего рода ожидаемая функция платформы), или вы обращались, переименовывали и перетасовывали все окрестностей вроде какого-то низкоуровневого сумасшедшего, играющего в богов, ТОГДА, возможно, вас больше заботит передача этих конкретных адресных ссылок, а не просто копий последних значений деталей дома ...

person Community    schedule 16.03.2018

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

«Схема

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

Это означает:

  • Вы можете изменить значение myObject внутри функции
  • Но вы не можете изменить то, на что myObject ссылается внутри функции, потому что point не myObject
  • Помните, что и point, и myObject являются ссылками, разными ссылками, однако эти ссылки указывают на одну и ту же new Point(0,0)
person Community    schedule 25.04.2016

Не повторюсь, но хочу указать на тех, кто все еще может быть сбит с толку после прочтения множества ответов:

  • pass by value в Java НЕ РАВНО pass by value в C ++, хотя это звучит так, вероятно, поэтому возникает путаница.

Разбивая это:

  • pass by value в C ++ означает передачу значения объекта (если объект), буквально копию объекта
  • pass by value в Java означает передачу значения адреса объекта (если объект), а не на самом деле значения (копии) объекта, например C ++
  • По pass by value в Java, работа с объектом (например, myObj.setName("new")) внутри функции оказывает влияние на объект вне функции; by pass by value в C ++, он не имеет НИКАКИХ эффектов на внешнее.
  • Однако, согласно pass by reference в C ++, работа с объектом в функции ДЕЙСТВИТЕЛЬНО оказывает влияние на внешний объект! Подобно (просто похоже, не то же самое) на pass by value в Java, не так ли? .. и люди всегда повторяют: в Java нет передачи по ссылке, = ›BOOM , начинается путаница ...

Итак, друзья, все сводится к разнице определения терминологии (между языками), вам просто нужно знать, как это работает, и все (хотя иногда немного сбивает с толку, как это называется, я признаю )!

person Community    schedule 26.12.2020
comment
В обоих языках передача по значению означает передачу значения объекта, если это объект. Это ни в коем случае не означает передачу адреса значения. Нет никакой разницы в терминологии. Нет случая, когда мы вызываем что-то, передаваемое по значению, и изменение значения в вызываемой функции изменяет значение в вызывающей стороне. Если вы вызываете функцию, подобную этой foo(bar) в java, значение bar никогда не изменяется - если bar является ссылкой на объект, его значение является идентификатором объекта, на который он ссылается, и независимо от того, что функция делает, она по-прежнему ссылается на тот же объект в вызывающей стороне. - person David Schwartz; 30.03.2021
comment
Я согласен с Дэвидом Шварцем: на самом деле терминологической разницы нет. Большая разница между Java и C ++ заключается в том, что в Java значение не может никогда быть целым объектом. Это всегда либо ссылка, либо примитивное значение. Вы просто не можете передать весь объект в Java вообще. - person Joachim Sauer; 21.04.2021

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

person Community    schedule 12.01.2009

Большая часть путаницы вокруг этой проблемы возникает из-за того, что Java попыталась переопределить, что означают «Передавать по значению» и «Передавать по ссылке». Важно понимать, что это отраслевые термины, и их нельзя правильно понять вне этого контекста. Они призваны помочь вам при написании кода и ценны для понимания, поэтому давайте сначала разберемся, что они означают.

Хорошее описание обоих можно найти здесь.

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

Передача по ссылке. Значение, полученное функцией, является ссылкой на объект, который использует вызывающий. Все, что функция делает с объектом, на который ссылается значение, будет видно вызывающему, и с этого момента он будет работать с этими изменениями.

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

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

И нет, специальный синтаксис C ++ «передача по ссылке» не является исключительным определением передачи по ссылке. Это чисто удобный синтаксис, предназначенный для того, чтобы вам не нужно было использовать синтаксис указателя после передачи указателя. Он все еще передает указатель, компилятор просто скрывает от вас этот факт. Он также по-прежнему передает этот указатель BY VALUE, компилятор просто скрывает это от вас.

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

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

person Community    schedule 12.05.2016
comment
В Java эти термины не были пересмотрены. Ни у кого нет. Он просто избегает использования термина C «указатель». - person user207421; 07.06.2016
comment
Эти термины существовали задолго до Java или C. Указатель был лишь методом реализации одного из них. Если вы примете определение Java для них, тогда они станут бессмысленными, потому что по этому определению каждый когда-либо созданный язык является только передачей по значению. - person Cdaragorn; 01.09.2016

Пытаясь добавить к этому еще больше, я подумал, что включу в эту тему раздел «Учебное пособие SCJP». Это из руководства, предназначенного для прохождения теста Sun / Oracle на поведение Java, так что это хороший источник для этого обсуждения.

Передача переменных в методы (цель 7.3)

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

Можно объявить методы, принимающие примитивы и / или ссылки на объекты. Вам необходимо знать, как (или если) вызывающая переменная может быть затронута вызываемым методом. Разница между ссылкой на объект и примитивными переменными при передаче в методы огромна и важна. Чтобы понять этот раздел, вам нужно хорошо разбираться в разделе заданий, описанном в первой части этой главы.

Передача переменных ссылки на объект

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

В этом примере мы будем использовать класс Dimension из пакета java.awt:

1. import java.awt.Dimension;
2. class ReferenceTest {
3.     public static void main (String [] args) {
4.         Dimension d = new Dimension(5,10);
5.         ReferenceTest rt = new ReferenceTest();
6.         System.out.println("Before modify() d.height = " + d.height);
7.         rt.modify(d);
8.         System.out.println("After modify() d.height = "
9.     }
10.
11.
12.
13.   }
14. }

Когда мы запускаем этот класс, мы видим, что метод modify () действительно смог изменить исходный (и единственный) объект Dimension, созданный в строке 4.

C:\Java Projects\Reference>java ReferenceTest
Before modify() d.height = 10
dim = 11
After modify() d.height = 11

Обратите внимание, когда объект Dimension в строке 4 передается методу modify (), любые изменения объекта, происходящие внутри метода, вносятся в объект, ссылка на который была передана. В предыдущем примере ссылочные переменные d и dim указывают на один и тот же объект.

Использует ли Java семантику передачи по значению?

Если Java передает объекты, передавая вместо этого ссылочную переменную, означает ли это, что Java использует передачу по ссылке для объектов? Не совсем, хотя вы часто слышите и читаете, что это так. Java фактически является передачей по значению для всех переменных, работающих в одной виртуальной машине. Передача по значению означает передачу по значению переменной. А это означает передачу за копией переменной! (Опять это слово копирует!)

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

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

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

        void bar() {
           Foo f = new Foo();
           doStuff(f);
        }
        void doStuff(Foo g) {
           g.setName("Boo");
           g = new Foo();
        }

переназначение g не переназначает f! В конце метода bar () были созданы два объекта Foo, на один ссылается локальная переменная f, а на один - локальная (аргументная) переменная g. Поскольку метод doStuff () имеет копию ссылочной переменной, у него есть способ перейти к исходному объекту Foo, например, вызвать метод setName (). Но у метода doStuff () нет способа добраться до ссылочной переменной f. Таким образом, doStuff () может изменять значения в объекте, на который ссылается f, но doStuff () не может изменять фактическое содержимое (битовый шаблон) f. Другими словами, doStuff () может изменить состояние объекта, на который ссылается f, но не может заставить f ссылаться на другой объект!

Передача примитивных переменных

Давайте посмотрим, что происходит, когда примитивная переменная передается в метод:

class ReferenceTest {
    public static void main (String [] args) {
      int a = 1;
      ReferenceTest rt = new ReferenceTest();
      System.out.println("Before modify() a = " + a);
      rt.modify(a);
      System.out.println("After modify() a = " + a);
    }
    void modify(int number) {
      number = number + 1;
      System.out.println("number = " + number);
    }
}

В этой простой программе переменная a передается методу с именем modify (), который увеличивает значение переменной на 1. Результат выглядит следующим образом:

  Before modify() a = 1
  number = 2
  After modify() a = 1

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

person Community    schedule 25.06.2013

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

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

class Example
{
    public static void test (Cat ref)
    {
        // 3 - <ref> is a copy of the reference <a>
        // both currently reference Grumpy
        System.out.println(ref.getName());

        // 4 - now <ref> references a new <Cat> object named "Nyan"
        ref = new Cat("Nyan");

        // 5 - this should print "Nyan"
        System.out.println( ref.getName() );
    }

    public static void main (String [] args)
    {
        // 1 - a is a <Cat> reference that references a Cat object in memory with name "Grumpy"
        Cat a = new Cat("Grumpy");

        // 2 - call to function test which takes a <Cat> reference
        test (a);

        // 6 - function call ends, and <ref> life-time ends
        // "Nyan" object has no references and the Garbage
        // Collector will remove it from memory when invoked

        // 7 - this should print "Grumpy"
        System.out.println(a.getName());
    }
}
person Community    schedule 02.06.2013
comment
«Передавать его внутреннюю ценность» бессмысленно. - person user207421; 17.09.2017
comment
@EJP, спасибо за заметку, извините за плохой английский с 2013 года, я все это отредактировал, если вы видите лучшую формулировку, вы можете предложить или отредактировать - person Khaled.K; 17.09.2017
comment
Я хотел бы добавить одну вещь. если вы изменили имя кота вместо создания нового, оно отразится в памяти даже после возврата метода - person ; 18.11.2017

Все передается по стоимости. Примитивы и ссылки на объекты. Но объекты можно изменять, если это позволяет их интерфейс.

Когда вы передаете объект методу, вы передаете ссылку, и объект может быть изменен реализацией метода.

void bithday(Person p) {
    p.age++;
}

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

void renameToJon(Person p) { 
    p = new Person("Jon"); // this will not work
}

jack = new Person("Jack");
renameToJon(jack);
sysout(jack); // jack is unchanged

По сути, «p» является ссылкой (указателем на объект) и не может быть изменена.

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

Напомним, все передается по значению.

person Community    schedule 19.04.2012

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

public static void dummyIncrease(int[] x, int y)
{
    x[0]++;
    y++;
}
public static void main(String[] args)
{
    int[] arr = {3, 4, 5};
    int b = 1;
    dummyIncrease(arr, b);
    // arr[0] is 4, but b is still 1
}

main()
  arr +---+       +---+---+---+
      | # | ----> | 3 | 4 | 5 |
      +---+       +---+---+---+
  b   +---+             ^
      | 1 |             | 
      +---+             |
                        |
dummyIncrease()         |
  x   +---+             |
      | # | ------------+
      +---+      
  y   +---+ 
      | 1 | 
      +---+ 
person Community    schedule 23.09.2013

Кратчайший ответ :)

  • В Java есть передача по значению (и передача по ссылке по значению).
  • В C # также есть передача по ссылке

В C # это достигается с помощью ключевых слов out и ref.

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

Далее следует пример передачи по ссылке (C #). Эта функция не существует в java.

class Example
{
    static void InitArray(out int[] arr)
    {
        arr = new int[5] { 1, 2, 3, 4, 5 };
    }

    static void Main()
    {
        int[] someArray;
        InitArray(out someArray);

        // This is true !
        boolean isTrue = (someArray[0] == 1);
    }
}

См. Также: библиотека MSDN ( C #): передача массивов по ссылке и out

См. Также: библиотека MSDN (C #): передача по значению и по ссылке

person Community    schedule 17.08.2013
comment
в java мы можем сделать: someArray = InitArray(someArray) при условии, что у нас есть это: static int [] InitArray( int[] arr){ ... return ...} - person Kachna; 27.02.2016
comment
Ты прав. Это возможная альтернатива простой передаче по ссылке. Но передача по ссылке может делать более мощные вещи. например он может присвоить несколько значений: например, int[] array1; int[] array2; InnitArrays(out array1, out array2); при условии, что вы создаете метод static void InitArray(out int[] a1, out int[] a2){...} - person bvdb; 27.02.2016

Простая программа

import java.io.*;
class Aclass
{
    public int a;
}
public class test
{
    public static void foo_obj(Aclass obj)
    {
        obj.a=5;
    }
    public static void foo_int(int a)
    {
        a=3;
    }
    public static void main(String args[])
    {
        //test passing an object
        Aclass ob = new Aclass();
        ob.a=0;
        foo_obj(ob);
        System.out.println(ob.a);//prints 5

        //test passing an integer
        int i=0;
        foo_int(i);
        System.out.println(i);//prints 0
    }
}

С точки зрения программиста C / C ++, java использует передачу по значению, поэтому для примитивных типов данных (int, char и т. Д.) Изменения в функции не отражаются в вызывающей функции. Но когда вы передаете объект и в функции меняете его члены-данные или вызываете функции-члены, которые могут изменять состояние объекта, вызывающая функция получит изменения.

person Community    schedule 22.12.2014
comment
Вы можете определить только один класс для каждого файла. Это не включает вложенные и внутренние классы. Учитывая, что это будет то, что будет читать новый программист, вы должны объяснить это пользователю; позволяя им дублировать код на своей машине. - person mrres1; 25.01.2015
comment
@ mrres1 Не совсем правильно. Вы можете определить только один общедоступный класс / интерфейс верхнего уровня для каждого файла. Поддержка нескольких классов в файле - это пережиток первой версии Java, в которой не было вложенных классов, но она все еще поддерживается, хотя ее часто осуждают. - person MrBackend; 19.03.2015

Есть очень простой способ понять это. Давайте возьмем C ++ по ссылке.

#include <iostream>
using namespace std;

class Foo {
    private:
        int x;
    public:
        Foo(int val) {x = val;}
        void foo()
        {
            cout<<x<<endl;
        }
};

void bar(Foo& ref)
{
    ref.foo();
    ref = *(new Foo(99));
    ref.foo();
}

int main()
{
   Foo f = Foo(1);
   f.foo();
   bar(f);
   f.foo();

   return 0;
}

Что в итоге?

1
1
99
99

Итак, после того, как bar () присвоил новое значение переданной «ссылке», он фактически изменил значение, которое было передано из самой main, объясняя последний вызов f.foo () из основной печати 99.

Теперь давайте посмотрим, что говорит java.

public class Ref {

    private static class Foo {
        private int x;

        private Foo(int x) {
            this.x = x;
        }

        private void foo() {
            System.out.println(x);
        }
    }

    private static void bar(Foo f) {
        f.foo();
        f = new Foo(99);
        f.foo();
    }

    public static void main(String[] args) {
        Foo f = new Foo(1);
        System.out.println(f.x);
        bar(f);
        System.out.println(f.x);
    }

}

Он говорит:

1
1
99
1

Вуаля, ссылка на Foo в main, которая была передана в bar, все еще не изменилась!

Этот пример ясно показывает, что java - это не то же самое, что C ++, когда мы говорим «передать по ссылке». По сути, java передает «ссылки» как «значения» функциям, то есть java передается по значению.

person Community    schedule 07.06.2016
comment
Есть ли проблема в вашей версии c ++, когда вы рискуете получить segfault, когда Foo(99) выходит за пределы области видимости, но вы ссылаетесь на нее в своем основном методе? - person matt; 15.06.2016
comment
Действительно. Ах, исходит от использования java в течение 10 лет. Но идея все еще актуальна. И я исправил это сейчас. - person Ravi Sanwal; 16.06.2016
comment
Я думаю, что предыдущий был лучше, потому что он компилировался. Мне было просто любопытно узнать о поведении, извините за это. - person matt; 16.06.2016
comment
Этот ответ помогает только тем, кто имеет опыт работы с C ++, кто хочет определять ссылку так, как вы, в соответствии с определением C ++. Это не всегда так. - person Loduwijk; 02.08.2017

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

package com.asok.cop.example.task;
public class Example {
    int data = 50;

    void change(int data) {
        data = data + 100;// changes will be in the local variable 
        System.out.println("after add " + data);
        }

    public static void main(String args[]) {
        Example op = new Example();
        System.out.println("before change " + op.data);
        op.change(500);
        System.out.println("after change " + op.data);
    }
}

Выход:

before change 50
after add 600
after change 50

как Майкл говорит в комментариях:

объекты по-прежнему передаются по значению, хотя операции с ними ведут себя как передача по ссылке. Учтите, что void changePerson(Person person){ person = new Person(); } ссылка вызывающего абонента на объект person останется неизменной. Сами объекты передаются по значению, но их члены могут быть затронуты изменениями. Чтобы быть истинной передачей по ссылке, мы должны иметь возможность переназначить аргумент новому объекту и отразить изменение в вызывающей стороне.

person Community    schedule 17.05.2018
comment
Описание java как передаваемого по значению сильно вводит в заблуждение. Для непримитивных типов Java использует передачу по значению ссылки. Передача по значению подразумевает, что значение копируется при передаче в метод. Это не так, ссылка скопирована. - person AutomatedMike; 03.05.2019

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

Возьмем, к примеру, метод badSwap ():

public void badSwap(int var1, int var2)
{
  int temp = var1;
  var1 = var2;
  var2 = temp;
}

Когда badSwap () возвращается, переменные, переданные в качестве аргументов, по-прежнему сохраняют свои исходные значения. Метод также не сработает, если мы изменим тип аргументов с int на Object, поскольку Java также передает ссылки на объекты по значению. Теперь вот где это становится сложным:

public 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("X: " + pnt1.x + " Y: " +pnt1.y); 
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X: " + pnt1.x + " Y:" + pnt1.y); 
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);  
}

Если мы выполним этот метод main (), мы увидим следующий результат:

X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0

Метод успешно изменяет значение pnt1, даже если оно передается по значению; однако поменять местами pnt1 и pnt2 не удается! Это главный источник путаницы. В методе main () pnt1 и pnt2 - это не что иное, как ссылки на объекты. Когда вы передаете pnt1 и pnt2 методу tricky (), Java передает ссылки по значению, как и любой другой параметр. Это означает, что ссылки, переданные в метод, на самом деле являются копиями исходных ссылок. На рисунке 1 ниже показаны две ссылки, указывающие на один и тот же объект после того, как Java передает объект методу.

введите здесь описание изображения
Рисунок 1. После передачи методу объект будет иметь как минимум две ссылки.

Java копирует и передает ссылку по значению, а не по объекту. Таким образом, манипуляции с методами изменят объекты, поскольку ссылки указывают на исходные объекты. Но поскольку ссылки являются копиями, обмен не удастся. Обмен ссылками на методы, но не на исходные ссылки. К сожалению, после вызова метода у вас остаются только исходные ссылки без замены. Чтобы замена прошла успешно вне вызова метода, нам нужно поменять местами исходные ссылки, а не копии.

person Community    schedule 05.11.2019

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

Пожалуйста, обратитесь к приведенному ниже примеру,

public class ObjectReferenceExample {

    public static void main(String... doYourBest) {
            Student student = new Student();
            transformIntoHomer(student);
            System.out.println(student.name);
    }

    static void transformIntoDuleepa(Student student) {
            student.name = "Duleepa";
    }
}
class Student {
    String name;
}

В данном случае это будет Duleepa!
Причина в том, что объектные переменные Java - это просто ссылки, указывающие на реальные объекты в куче памяти. Следовательно, даже если Java передает параметры методам по значению, если переменная указывает на ссылку на объект, реальный объект также будет изменен.

person Community    schedule 18.10.2020
comment
Запуск этой программы должен помочь любому понять эту концепцию. pastebin.com/VEc8NQcX - person Mohith7548; 03.11.2020
comment
В этом примере вы не скопировали объект Student, поэтому я думаю, что утверждение, что передача копии значения также изменяет реальное значение объекта, вводит в заблуждение. То, что вы копируете и передаете по значению, является ссылкой на объект. Объект продолжает жить в куче, а их всего один. Вот почему, когда вы используете новую ссылку для изменения объекта, вы изменяете ее для всех остальных, у кого есть ссылка на объект. Есть только один объект. Когда аргумент функции является примитивным типом, а не ссылкой на объект, он также копируется. - person Chrispher; 14.11.2020

Мистер @Scott Stanchfield написал отличный ответ. Вот класс, который вы хотели бы проверить, что он имел в виду:

public class Dog {

    String dog ;
    static int x_static;
    int y_not_static;

    public String getName()
    {
        return this.dog;
    }

    public Dog(String dog)
    {
        this.dog = dog;
    }

    public void setName(String name)
    {
        this.dog = name;
    }

    public static void foo(Dog someDog)
    {
        x_static = 1;
        // y_not_static = 2;  // not possible !!
        someDog.setName("Max");     // AAA
        someDog = new Dog("Fifi");  // BBB
        someDog.setName("Rowlf");   // CCC
    }

    public static void main(String args[])
    {
        Dog myDog = new Dog("Rover");
        foo(myDog);
        System.out.println(myDog.getName());
    }
}

Итак, мы передаем из main () собаку по имени Rover, затем мы назначаем новый адрес указателю, который мы передали, но в конце имя собаки не Rover, и не Fifi, и, конечно, не Rowlf, но Max.

person Community    schedule 22.01.2014

Разберитесь в двух шагах:

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

Если вы хотите изменить значение за ссылкой, вы только объявите новую переменную в стеке с тем же именем 'd'. Посмотрите на ссылки со знаком @, и вы обнаружите, что ссылка была изменена.

public static void foo(Dog d) {
  d.Name = "belly";
  System.out.println(d); //Reference: Dog@1540e19d

  d = new Dog("wuffwuff");
  System.out.println(d); //Dog@677327b6
}
public static void main(String[] args) throws Exception{
  Dog lisa = new Dog("Lisa");
  foo(lisa);
  System.out.println(lisa.Name); //belly
}
person Community    schedule 10.07.2014

Я попытался упростить приведенные выше примеры, сохранив только суть проблемы. Позвольте мне представить это как историю, которую легко запомнить и правильно применить. История гласит: у вас есть домашняя собака Джимми, хвост которой составляет 12 дюймов. Вы оставляете его ветеринару на несколько недель, пока едете за границу.

Ветеринару не нравится длинный хвост Джимми, поэтому он хочет сократить его вдвое. Но, будучи хорошим ветеринаром, он знает, что не имеет права калечить чужих собак. Поэтому он сначала создает клон собаки (с ключевым словом new) и отрезает этому клону хвост. Когда собака, наконец, вернется к вам, у нее останется прежний 12-дюймовый хвост. Счастливый конец !

В следующий раз, когда вы путешествуете, вы невольно отведите собаку к злому ветеринару. Он также ненавидит длинные хвосты, поэтому сокращает их до жалких 2 дюймов. Но он делает это с твоим дорогим Джимми, а не его клоном. Когда вы возвращаетесь, вы потрясены, увидев, как Джимми жалко виляет двухдюймовым окурком.

Мораль истории: передавая своего питомца, вы передаете ветеринару полную и неограниченную опеку над ним. Он волен устроить им какой-нибудь хаос. Передача по значению, по ссылке, по указателю - все это просто технические споры. Если ветеринар сначала не клонирует его, он в конечном итоге изувечит оригинальную собаку.

public class Doggie {

    public static void main(String...args) {
        System.out.println("At the owner's home:");
        Dog d = new Dog(12);
        d.wag();
        goodVet(d);
        System.out.println("With the owner again:)");
        d.wag();
        badVet(d);
        System.out.println("With the owner again(:");
        d.wag();
    }

    public static void goodVet (Dog dog) {
        System.out.println("At the good vet:");
        dog.wag();
        dog = new Dog(12); // create a clone
        dog.cutTail(6);    // cut the clone's tail
        dog.wag();
    }

    public static void badVet (Dog dog) {
        System.out.println("At the bad vet:");
        dog.wag();
        dog.cutTail(2);   // cut the original dog's tail
        dog.wag();
    }    
}

class Dog {

    int tailLength;

    public Dog(int originalLength) {
        this.tailLength = originalLength;
    }

    public void cutTail (int newLength) {
        this.tailLength = newLength;
    }

    public void wag()  {
        System.out.println("Wagging my " +tailLength +" inch tail");
    }
}

Output:
At the owner's home:
Wagging my 12 inch tail
At the good vet:
Wagging my 12 inch tail
Wagging my 6 inch tail
With the owner again:)
Wagging my 12 inch tail
At the bad vet:
Wagging my 12 inch tail
Wagging my 2 inch tail
With the owner again(:
Wagging my 2 inch tail
person Community    schedule 27.01.2017

В Java есть обходной путь для справки. Позвольте мне объяснить на этом примере:

public class Yo {
public static void foo(int x){
    System.out.println(x); //out 2
    x = x+2;
    System.out.println(x); // out 4
}
public static void foo(int[] x){
    System.out.println(x[0]); //1
    x[0] = x[0]+2;
    System.out.println(x[0]); //3
}
public static void main(String[] args) {
    int t = 2;
    foo(t);
    System.out.println(t); // out 2 (t did not change in foo)

    int[] tab = new int[]{1};
    foo(tab);
    System.out.println(tab[0]); // out 3 (tab[0] did change in foo)
}}

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

person Community    schedule 06.10.2014
comment
Чтобы понять это, нужно понимать, что, в отличие от многих языков Java, массив - это сам Object. - person v010dya; 21.04.2021

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

Возьмем, к примеру, метод badSwap ():

    public void badSwap(int var1, int
 var2{ int temp = var1; var1 = var2; var2 =
 temp; }

Когда badSwap () возвращается, переменные, переданные в качестве аргументов, по-прежнему сохраняют свои исходные значения. Метод также не сработает, если мы изменим тип аргументов с int на Object, поскольку Java также передает ссылки на объекты по значению. Теперь вот где это становится сложным:

public 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("X:
 " + pnt1.x + " Y: " +pnt1.y);

     System.out.println("X: " + pnt2.x + " Y:
 " +pnt2.y); System.out.println(" ");

     tricky(pnt1,pnt2);
 System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);

     System.out.println("X: " + pnt2.x + " Y: " +pnt2.y); }

Если мы выполним этот метод main (), мы увидим следующий результат:

X: 0 Y: 0 X: 0 Y: 0 X: 100 Y: 100 X: 0 Y: 0

Метод успешно изменяет значение pnt1, даже если оно передается по значению; однако поменять местами pnt1 и pnt2 не удается! Это главный источник путаницы. В методе main () pnt1 и pnt2 - это не что иное, как ссылки на объекты. Когда вы передаете pnt1 и pnt2 методу tricky (), Java передает ссылки по значению, как и любой другой параметр. Это означает, что ссылки, переданные в метод, на самом деле являются копиями исходных ссылок. На рисунке 1 ниже показаны две ссылки, указывающие на один и тот же объект после того, как Java передает объект методу.

Java копирует и передает ссылку по значению, а не по объекту. Таким образом, манипуляции с методом изменят объекты, поскольку ссылки указывают на исходные объекты. Но поскольку ссылки являются копиями, обмен не удастся. Как показано на рисунке 2, ссылки на методы меняются местами, но не исходные ссылки. К сожалению, после вызова метода у вас остаются только исходные ссылки без замены. Чтобы замена прошла успешно вне вызова метода, нам нужно поменять местами исходные ссылки, а не копии.

person Community    schedule 26.09.2016

На мой взгляд, «передача по значению» - ужасный способ однозначно описать два похожих, но разных события. Думаю, им следовало сначала спросить меня.

С примитивами мы передаем фактическое значение примитива в метод (или конструктор), будь то целое число «5», символ «c» или что-то еще. Это фактическое значение затем становится его собственным локальным примитивом. Но с объектами все, что мы делаем, - это даем одному и тому же объекту дополнительную ссылку (локальную ссылку), так что теперь у нас есть две ссылки, указывающие на один и тот же объект.

Надеюсь, это простое объяснение поможет.

person Community    schedule 24.06.2011
comment
«Передача по значению» - это стандартный термин в компьютерных науках, который используется с 1950-х годов. Нет смысла жаловаться на это сейчас. - person user207421; 07.06.2016

Итог по передаче по значению: вызываемый метод не может изменить переменную вызывающего, хотя для переменных ссылки на объект вызываемый метод может изменить объект, на который ссылается переменная. В чем разница между изменением переменной и изменением объекта? Для объектных ссылок это означает, что вызываемый метод не может переназначить исходную ссылочную переменную вызывающей стороны и сделать ее ссылкой на другой объект или значение null.

Я взял этот код и объяснение из книги по сертификации Java и внес некоторые незначительные изменения.
Я думаю, что это хорошая иллюстрация передачи объекта по значению. В приведенном ниже коде переназначение g не переназначает f! В конце метода bar () были созданы два объекта Foo, на один ссылается локальная переменная f, а на один - локальная (аргументная) переменная g.

Поскольку метод doStuff () имеет копию ссылочной переменной, у него есть способ перейти к исходному объекту Foo, например, вызвать метод setName (). Но у метода doStuff () нет способа добраться до ссылочной переменной f. Таким образом, doStuff () может изменять значения в объекте, на который ссылается f, но doStuff () не может изменять фактическое содержимое (битовый шаблон) f. Другими словами, doStuff () может изменить состояние объекта, на который ссылается f, но не может заставить f ссылаться на другой объект!

package test.abc;

public class TestObject {

    /**
     * @param args
     */
    public static void main(String[] args) {
        bar();
    }

    static void bar() {
        Foo f = new Foo();
        System.out.println("Object reference for f: " + f);
        f.setName("James");
        doStuff(f);
        System.out.println(f.getName());
        //Can change the state of an object variable in f, but can't change the object reference for f.
        //You still have 2 foo objects.
        System.out.println("Object reference for f: " + f);
        }

    static void doStuff(Foo g) {
            g.setName("Boo");
            g = new Foo();
            System.out.println("Object reference for g: " + g);
        }
}


package test.abc;

public class Foo {
    public String name = "";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Обратите внимание, что ссылка на объект в выводе консоли ниже не изменилась:

Вывод в консоль:

Ссылка на объект для f: test.abc.Foo@62f72617

Ссылка на объект для g: test.abc.Foo@4fe5e2c3

Ссылка на объект Boo для f: test.abc.Foo@62f72617

person Community    schedule 04.09.2013

Java передает все по значению !!

// создаем объект, передавая имя и возраст:

PersonClass variable1 = new PersonClass("Mary", 32);

PersonClass variable2;

// И переменная 2, и переменная 1 теперь ссылаются на один и тот же объект

variable2 = variable1; 


PersonClass variable3 = new PersonClass("Andre", 45);

// теперь переменная1 указывает на переменную3

variable1 = variable3;

// ЧТО ЭТО ВЫХОДИТ?

System.out.println(variable2);
System.out.println(variable1);

Mary 32
Andre 45

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

веб-страница

person Community    schedule 26.02.2015
comment
На самом деле это ничего не объясняет в отношении потенциала Java по свойству ref / by val. - person Mox; 18.01.2017

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

Класс S

class S{
String name="alam";
public void setName(String n){
this.name=n; 
}}

Образец класса

    public class Sample{
    public static void main(String args[]){
    S s=new S();
    S t=new S();
    System.out.println(s.name);
    System.out.println(t.name);
    t.setName("taleev");
    System.out.println(t.name);
    System.out.println(s.name);
    s.setName("Harry");
    System.out.println(t.name);
    System.out.println(s.name);
    }}

Вывод

алам

алам

Талеев

алам

Талеев

Гарри

Поскольку мы определили класс S с именем переменной экземпляра со значением Taleev, поэтому для всех объектов, которые мы инициализируем из него, будет переменная имени со значением Taleev, но если мы изменим значение имени любых объектов, тогда он меняет имя только этой копии класса (Object) не для каждого класса, поэтому после этого также, когда мы делаем System.out.println (s.name) он печатает талеев, только мы не можем изменить значение имени, которое мы определили изначально, и значение, которое мы изменяем, является значением объекта, а не значением переменной экземпляра, поэтому, как только мы определим переменную экземпляра, мы не могу это изменить

Думаю, именно так это показывает, что java имеет дело с значениями, но не с ссылками.

Распределение памяти для примитивных переменных можно понять с помощью this

person Community    schedule 16.11.2016

Сначала давайте разберемся с распределением памяти в Java: стек и куча являются частью памяти, которую JVM выделяет для различных целей. Память стека заранее выделяется потоку, когда он создается, поэтому поток не может получить доступ к стеку другого потока. Но куча доступна всем потокам в программе.

Для потока Stack хранит все локальные данные, метаданные программы, данные примитивного типа и ссылки на объекты. Причем, Heap отвечает за хранение реального объекта.

Book book = new Book("Effective Java");

В приведенном выше примере ссылочной переменной является «книга», которая хранится в стеке. Экземпляр, созданный оператором new -> new Book («Эффективная Java»), сохраняется в Heap. Переменная ref "book" имеет адрес объекта, размещенного в Heap. Допустим, адрес 1001.

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

Рассмотрите возможность передачи примитивного типа данных, то есть int, float, double и т. Д.

public class PrimitiveTypeExample { 
    public static void main(string[] args) {
       int num = 10;
       System.out.println("Value before calling method: " + num);
       printNum(num);
       System.out.println("Value after calling method: " + num);
    }
    public static void printNum(int num){
       num = num + 10;
       System.out.println("Value inside printNum method: " + num);
    }
}

Вывод: Значение до вызова метода: 10 Значение внутри метода printNum: 20 Значение после вызова метода: 10

int num = 10; -> это выделяет память для int в стеке запущенного потока, потому что это примитивный тип. Теперь, когда вызывается printNum (..), в том же потоке создается частный стек. Когда "num" передается этому методу, копия "num" создается в кадре стека методов. число = число + 10; -> это добавляет 10 и изменяет переменную int в кадре стека методов. Следовательно, исходное число вне кадра стека методов остается неизменным.

Рассмотрим пример передачи объекта настраиваемого класса в качестве аргумента.

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

В приведенном выше примере переменная ref "book" находится в стеке потока, выполняющего программу, а объект класса Book создается в пространстве кучи, когда программа выполняет new Book (). Это место в памяти в куче называется «книгой». Когда «книга» передается в качестве аргумента метода, копия «книги» создается в частном стековом фрейме метода в том же стеке потока. Следовательно, скопированная ссылочная переменная указывает на тот же объект класса «Книга» в куче.

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

Ссылочная переменная в кадре стека методов устанавливает новое значение для того же объекта. Следовательно, это отражается, когда исходная переменная ref "book" получает свое значение. Обратите внимание, что в случае передачи ссылочной переменной, если она снова инициализируется в вызываемом методе, тогда она указывает на новое место в памяти, и любая операция не влияет на предыдущий объект в куче.

Следовательно, когда что-либо передается в качестве аргумента метода, это всегда сущность Stack - либо примитивная, либо ссылочная переменная. Мы никогда не передаем то, что хранится в куче. Следовательно, в Java мы всегда передаем значение в стеке, и оно передается по значению.

person Community    schedule 22.08.2019

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 Давайте разберемся шаг за шагом:

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

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

new PassByValue().changeValue(t);

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

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

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

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

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, как показано ниже:

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

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

person Community    schedule 21.11.2020

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

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

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

person Community    schedule 03.12.2013

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

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

Это важно, так как это экономит много памяти и увеличивает скорость.

person Community    schedule 17.07.2019

public class Test {

    static class Dog {
        String name;

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Dog other = (Dog) obj;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }

        public String getName() {
            return name;
        }

        public void setName(String nb) {
            this.name = nb;
        }

        Dog(String sd) {
            this.name = sd;
        }
    }
    /**
     * 
     * @param args
     */
    public static void main(String[] args) {
        Dog aDog = new Dog("Max");

        // we pass the object to foo
        foo(aDog);
        Dog oldDog = aDog;

        System.out.println(" 1: " + aDog.getName().equals("Max")); // false
        System.out.println(" 2 " + aDog.getName().equals("huahua")); // false
        System.out.println(" 3 " + aDog.getName().equals("moron")); // true
        System.out.println(" 4 " + " " + (aDog == oldDog)); // true

        // part2
        Dog aDog1 = new Dog("Max");

        foo(aDog1, 5);
        Dog oldDog1 = aDog;

        System.out.println(" 5 : " + aDog1.getName().equals("huahua")); // true
        System.out.println(" part2 : " + (aDog1 == oldDog1)); // false

        Dog oldDog2 = foo(aDog1, 5, 6);
        System.out.println(" 6 " + (aDog1 == oldDog2)); // true
        System.out.println(" 7 " + (aDog1 == oldDog)); // false
        System.out.println(" 8 " + (aDog == oldDog2)); // false
    }

    /**
     * 
     * @param d
     */
    public static void foo(Dog d) {
        System.out.println(d.getName().equals("Max")); // true

        d.setName("moron");

        d = new Dog("huahua");
        System.out.println(" -:-  " + d.getName().equals("huahua")); // true
    }

    /**
     * 
     * @param d
     * @param a
     */
    public static void foo(Dog d, int a) {
        d.getName().equals("Max"); // true

        d.setName("huahua");
    }

    /**
     * 
     * @param d
     * @param a
     * @param b
     * @return
     */
    public static Dog foo(Dog d, int a, int b) {
        d.getName().equals("Max"); // true
        d.setName("huahua");
        return d;
    }
}

Пример кода, демонстрирующий влияние изменений объекта на различные функции.

person Community    schedule 27.07.2019

Я бы сказал по-другому:

В java передаются ссылки (но не объекты), и эти ссылки передаются по значению (сама ссылка копируется, и в результате у вас есть 2 ссылки, и у вас нет контроля по 1-й ссылке в методе).

Просто скажу: передача по значению может быть недостаточно понятной для новичков. Например, в Python такая же ситуация, но есть статьи, в которых описывается, что они называют это pass-by-reference, используются только ссылки на причины.

person Community    schedule 10.10.2020
comment
Четко и ясно! - person Abhishek Attri; 22.12.2020

Для простоты и многословности Это pass reference by value:

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
}
person Community    schedule 28.04.2021

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

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

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

String name="Mehrose";  // name referencing to 100

ChangeContenet(String name){
 name="Michael"; // refernce has changed to 1001

} 
System.out.print(name);  //displays Mehrose

Довольно просто, потому что, как я уже упоминал, вам не разрешено изменять скопированную ссылку в вызывающей функции. Но проблема заключается в массиве, когда вы передаете массив String / Object. Покажи нам.

String names[]={"Mehrose","Michael"};

changeContent(String[] names){
  names[0]="Rose";
  names[1]="Janet"

}

System.out.println(Arrays.toString(names)); //displays [Rose,Janet]

Как мы уже говорили, мы не можем изменить скопированную ссылку в вызове функции, и мы также видели в случае одного объекта String. Причина в том, что переменная names [] ссылается на, скажем, 200, а имена [0] ссылаются на 205 и так далее. Вы видите, что мы не изменили ссылку names [], она по-прежнему указывает на старую ссылку все еще после вызова функции, но теперь ссылка names [0] и names [1] была изменена. Мы по-прежнему придерживаемся нашего определения, что мы не можем изменить ссылку на ссылочную переменную, поэтому мы этого не сделали.

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

Ты не можешь этого сделать

Student student1= new Student("Mehrose");

changeContent(Student Obj){
 obj= new Student("Michael") //invalid
 obj.setName("Michael")  //valid

}
person Community    schedule 21.09.2019

Язык программирования 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.
person Community    schedule 14.11.2013
comment
Это очень вводит в заблуждение. Вы, безусловно, можете изменить значение аргумента из метода. - person Gray; 28.11.2017

Вот более точное определение:

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

Итак, в C / C ++ вы можете создать функцию, которая меняет местами два значения, переданные с использованием ссылок:

void swap(int& a, int& b) 
{
    int tmp = a; 
    a = b; 
    b = tmp; 
}

Вы можете видеть, что у него есть уникальная ссылка на a и b, поэтому у нас нет копии, tmp просто хранит уникальные ссылки.

Та же функция в java не имеет побочных эффектов, передача параметров такая же, как в приведенном выше коде, без ссылок.

Хотя java работает с указателями / ссылками, параметры не являются уникальными указателями, в каждой атрибуции они копируются, а не просто назначаются как C / C ++

person Community    schedule 08.03.2021

Пожалуйста прочтите это.

Многие языки программирования позволяют передавать параметры по ссылке или по значению. В Java мы можем передавать параметры только по значению. Это накладывает некоторые ограничения, а также вызывает вопросы. Например, если в методе изменяется значение параметра, что происходит со значением после выполнения метода? Вы также можете задаться вопросом, как Java управляет значениями объектов в куче памяти. Этот Java Challenger поможет вам решить эти и другие распространенные вопросы о ссылках на объекты в Java.

Для получения дополнительной информации:

https://www.javaworld.com/article/3512039/does-java-pass-by-reference-or-pass-by-value.html

person Community    schedule 13.03.2020

Есть только две версии:

  • Вы можете передать значение, например (4,5)
  • Вы можете передать адрес, например 0xF43A

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

В C ++ вы можете делать следующее:

Point p = Point(4,5);

Это резервирует 8 байтов в стеке и сохраняет в нем (4,5).

Point *x = &p;

Это резервирует 4 байта в стеке и сохраняет в нем 0xF43A.

Point &y = p;

Это резервирует 4 байта в стеке и сохраняет в нем 0xF43A.

  1. Я думаю, все согласятся, что вызов f (p) - это передача по значению, если определение f равно f (точка p). В этом случае зарезервированы дополнительные 8 байтов и (4,5) скопированы в них. Когда f меняет p, оригинал гарантированно не изменится, когда f вернется.

  2. Я думаю, что все согласятся, что вызов f (p) является передачей по ссылке, если определение f равно f (Point & p). В этом случае зарезервированы дополнительные 4 байта и в них копируется 0xF43A. Когда f меняет p, гарантируется, что оригинал будет изменен, когда f вернется.

  3. Вызов f (& p) также передается по ссылке, если определение f - f (Point * p). В этом случае зарезервированы дополнительные 4 байта и в них копируется 0xF43A. Когда f меняет * p, гарантируется, что оригинал будет изменен, когда f вернется.

  4. Вызов f (x) также передается по ссылке, если определение f - f (Point * p). В этом случае зарезервированы дополнительные 4 байта и в них копируется 0xF43A. Когда f меняет * p, гарантируется, что оригинал будет изменен, когда f вернется.

  5. Вызов f (y) также передается по ссылке, если определение f - f (Point & p). В этом случае зарезервированы дополнительные 4 байта и в них копируется 0xF43A. Когда f меняет p, гарантируется, что оригинал будет изменен, когда f вернется.

Конечно, то, что происходит после передачи, отличается, но это только языковая конструкция. В случае указателя вы должны использовать - ›для доступа к элементам, а в случае ссылок, которые вы должны использовать .. Если вы хотите поменять местами значения оригинала, вы можете сделать tmp = a; а = б; b = tmp; в случае ссылок и tmp = * a; * b = tmp; * a = tmp для указателей. А в Java вам нужно: tmp.set (a); a.set (b); b.set (tmp). Сосредоточиться на операторе присваивания глупо. Вы можете сделать то же самое на Java, если напишете немного кода.

Таким образом, Java передает примитивы по значениям и объекты по ссылкам. И Java копирует значения для этого, как и C ++.

Для полноты:

Point p = new Point(4,5);

Это резервирует 4 байта в стеке и сохраняет в нем 0xF43A, а также резервирует 8 байтов в куче и сохраняет в нем (4,5).

Если вы хотите поменять местами места в памяти вот так

void swap(int& a, int& b) {
    int *tmp = &a;
    &a = &b;
    &b = tmp;
}

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

person Community    schedule 16.03.2021
comment
Один из наиболее полных ответов находится внизу. Ваш № 3 лучше всего описывает ситуацию на Java. - person v010dya; 21.04.2021

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

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

(Таким образом, вы можете изменить исходный объект, но не можете получить доступ к исходной ссылке)

person Community    schedule 06.03.2021

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

Этот код показывает, как можно сделать что-то вроде этого:

public class Test
{
    private static void needValue(SomeObject so) throws CloneNotSupportedException
    {
        SomeObject internalObject = so.clone();
        so=null;
        
        // now we can edit internalObject safely.
        internalObject.set(999);
    }
    public static void main(String[] args)
    {
        SomeObject o = new SomeObject(5);
        System.out.println(o);
        try
        {
            needValue(o);
        }
        catch(CloneNotSupportedException e)
        {
            System.out.println("Apparently we cannot clone this");
        }
        System.out.println(o);
    }
}

public class SomeObject implements Cloneable
{
    private int val;
    public SomeObject(int val)
    {
        this.val = val;
    }
    public void set(int val)
    {
        this.val = val;
    }
    public SomeObject clone()
    {
        return new SomeObject(val);
    }
    public String toString()
    {
        return Integer.toString(val);
    }
}

Здесь у нас есть функция needValue, и она сразу же создает клон объекта, который необходимо реализовать в классе самого объекта, и этот класс нужно пометить как Cloneable. После этого не обязательно устанавливать so в null, но я сделал это здесь, чтобы показать, что мы не собираемся использовать эту ссылку после этого.

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

person Community    schedule 23.04.2021
comment
Примечание: безопасно теперь, когда мы можем безопасно редактировать internalObject, зависит от реализации метода clone() (т.е. глубокий или неглубокий) и от того, насколько далеко вниз по дереву объектов ваши изменения влияют. Однако для этого простого примера это правильно. - person siegi; 24.04.2021