Значение массива не изменено в функции [дубликат]

Вы создаете регулярное выражение, передавая строку конструктору RegExp.

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

5518
задан 21 revs, 17 users 15% 11 July 2018 в 11:31
поделиться

30 ответов

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

Java Spec говорит, что все в Java является передачей по значению. В Java нет такой вещи, как «pass-by-reference».

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

Dog myDog;

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

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

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
}

let's посмотрите, что происходит.

  • параметр someDog установлен на значение 42
  • в строке «AAA» someDog, после чего он Dog указывает на точки к объекту Dog по адресу 42), что Dog (тот по адресу 42) предлагается изменить свое имя на Max
  • в строке «BBB», создается новый Dog. Предположим, что он находится по адресу 74, мы присваиваем параметру someDog значение 74
  • в строке «CCC». Некоторое число следит за Dog, которое указывает (объект Dog по адресу 74), что Dog (тот, который находится по адресу 74), предлагается изменить его имя на Rowlf
  • , тогда мы вернем

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

Изменено myDog?

Имеется ключ.

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

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

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

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

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

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

2647
ответ дан 11 revs, 6 users 73% 17 August 2018 в 11:42
поделиться
  • 1
    Вот почему общий рефрен «Java не имеет указателей». настолько вводит в заблуждение. – Beska 2 April 2009 в 18:52
  • 2
    Вы ошибаетесь, имхо. «Помня о том, что myDog является указателем, а не фактическим Собаком, ответ НЕТ. myDog все еще имеет значение 42; он все еще указывает на оригинальную Собака. & quot; myDog имеет значение 42, но его аргумент name теперь содержит «Max», а не «Rover». на линии // AAA. – Özgür 6 April 2009 в 06:22
  • 3
    Подумайте об этом таким образом. У кого-то есть адрес Энн-Арбор, Мичиган (мой родной город, GO BLUE!) На листе бумаги под названием «annArborLocation». Вы скопируете его на листе бумаги под названием «myDestination». Вы можете перейти к & quot; myDestination & quot; и посадить дерево. Возможно, вы изменили что-то о городе в этом месте, но он не меняет LAT / LON, который был написан на любой бумаге. Вы можете изменить LAT / LON на "myDestination" но он не изменяет «annArborLocation». Это помогает? – Scott Stanchfield 23 April 2009 в 14:06
  • 4
    @Scott Stanchfield: Я прочитал вашу статью около года назад, и это действительно помогло мне разобраться. Благодаря! Могу ли я смиренно предложить небольшое дополнение: вы должны упомянуть, что на самом деле существует конкретный термин, который описывает эту форму «вызывать по значению, где значение является ссылкой», который был изобретен Барбарой Лисковым для описания стратегии оценки ее языка CLU в 1974 году, чтобы избежать путаницы, такой как та, на которую ссылается ваша статья: вызов путем совместного использования (иногда называемый вызов по объекту -sharing или просто вызов по объекту ), который в значительной степени отлично описывает семантику. – Jörg W Mittag 7 September 2010 в 23:12
  • 5
    @Gevorg. Языки C / C ++ не владеют концепцией «указателя». Существуют и другие языки, которые используют указатели, но не допускают те же типы манипуляций указателями, которые допускает C / C ++. Java имеет указатели; они просто защищены от озорства. – Scott Stanchfield 30 December 2011 в 20:30

Java - это вызов по значению.

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

  • Вы всегда передаете копию бит значения ссылки!
  • Если это примитивный тип данных, эти биты содержат значение самого примитивного типа данных. Поэтому, если мы изменим значение заголовка внутри метода, то оно не отражает изменения вне.
  • Если это тип данных объекта, например Foo foo = new Foo (), тогда в этом случае копия адреса объекта проходит как ярлык файла, предположим, что у нас есть текстовый файл abc.txt на C: \ desktop, и предположим, что мы делаем ярлык тот же файл и поместите его внутри C: \ desktop \ abc-shortcut, поэтому, когда вы получаете доступ к файлу из C: \ desktop \ abc.txt и пишите 'Stack Overflow' и закрываете файл, и снова вы открываете файл из ярлыка, тогда вы пишете «является крупнейшим онлайн-сообществом для программистов, чтобы узнать», тогда общее изменение файла будет «Stack Overflow - это самое большое онлайн-сообщество для программистов, чтобы учиться», что означает, что не имеет значения, откуда вы открываете файл e, каждый раз, когда мы обращались к одному и тому же файлу, здесь мы можем считать Foo как файл и предположим, что foo хранится на адресе 123hd7h (исходный адрес, например C: \ desktop \ abc.txt) и 234jdid (скопированный адрес, например C: \ desktop \ abc-shortcut, который фактически содержит исходный адрес файла внутри). Поэтому для лучшего понимания создайте файл ярлыка и почувствуйте ...
39
ответ дан 16 revs 17 August 2018 в 11:42
поделиться

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

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

  • Java передает ему параметры по значению
  • «по значению» - единственный способ в java передать параметр методу
  • , используя методы из объекта, заданного как параметр, будет изменять объект, поскольку ссылки указывают на исходные объекты. (если этот метод сам изменяет некоторые значения)
46
ответ дан 2 revs 17 August 2018 в 11:42
поделиться

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

34
ответ дан 2 revs, 2 users 50% 17 August 2018 в 11:42
поделиться
  • 1
    Я считаю, что ваше второе-последнее предложение очень вводит в заблуждение. Неверно, что «все объекты в Java являются ссылками». Только те ссылки относятся к тем объектам, которые являются ссылками. – Dawood ibn Kareem 25 January 2017 в 11:09

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

Чтобы сократить длинный короткий текст:

Для тех, кто приходит из C #: нет параметра «out» .

Для тех, кто приходит из PASCAL: нет параметра «var».

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

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

19
ответ дан 2 revs, 2 users 71% 17 August 2018 в 11:42
поделиться
  • 1
    – sakhunzai 30 March 2017 в 05:41
  • 2
    Таким образом, объект может быть изменен с помощью его публичных интерфейсов, но не может быть заменен другим, а также тем, что этот java достигает наилучшего из обоих миров – sakhunzai 30 March 2017 в 06:00

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();
}
29
ответ дан 2 revs, 2 users 86% 17 August 2018 в 11:42
поделиться
  • 1
    Это самый простой и простой способ увидеть, что Java проходит по значению. Значение obj (null) передано на init, а не на ссылку obj. – David Schwartz 10 June 2017 в 23:24

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

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.

129
ответ дан 2 revs, 2 users 97% 17 August 2018 в 11:42
поделиться
  • 1
    Я бы сказал, что бар - это копия ссылочного базиса (или базового псевдонима), который первоначально указывает на тот же объект. – MaxZoom 11 February 2015 в 06:36

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

Это выглядит следующим образом:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    // 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 
}

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");
    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // 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 (кроме случаев, когда d изменен, чтобы указать на другой экземпляр Dog, например d = new Dog("Boxer")), .

4756
ответ дан 27 revs, 25 users 35% 17 August 2018 в 11:42
поделиться
  • 1
    Разве это не путает проблему с внутренними деталями? Не существует принципиальной разницы между «передачей ссылки» и «передачей значения ссылки», предполагая, что вы имеете в виду «значение внутреннего указателя на объект». – izb 8 September 2008 в 15:58
  • 2
    Но есть тонкая разница. Посмотрите на первый пример. Если бы это было чисто по ссылке, aDog.name было бы «Fifi». Это не так: ссылка, которую вы получаете, является ссылкой на значение, которая, если перезапись будет восстановлена ​​при выходе из функции. – erlando 11 September 2008 в 07:55
  • 3
    @Lorenzo: Нет, в Java все передается по значению. Примитивы передаются по значению, а ссылки на объекты передаются по значению. Сами объекты никогда не передаются методу, но объекты всегда находятся в куче, и эта процедура передается только ссылкой на объект. – Esko Luontola 13 February 2009 в 00:02
  • 4
    Моя попытка улучшить визуализацию объекта: Представьте себе воздушный шар. Вызов fxn похож на привязку второй строки к воздушному шару и передачу строки в fxn. parameter = new Balloon () отрежет эту строку и создаст новый воздушный шар (но это не повлияет на исходный воздушный шар). параметр.pop () все равно будет всплывать, потому что он следует за строкой в ​​том же оригинальном шаре. Java передается по значению, но переданное значение не является глубоким, оно находится на самом высоком уровне, то есть примитиве или указателе. Не путайте это с глубоким сквозным значением, где объект полностью клонирован и передан. – dhackner 20 October 2010 в 17:38
  • 5
    Что вводит в заблуждение, так это то, что ссылки на объекты являются на самом деле указателями. В начале SUN называли их указателями. Затем маркетинг сообщил, что «указатель» было плохим словом. Но вы все еще видите «правильный». номенклатура в NullPointerException. – Prof. Falken 9 February 2011 в 10:46

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

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

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

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

Или из википедии, на тему прохода -by-reference

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

И по вопросу прохода -value

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

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

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

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

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

Рассмотрим ссылочные типы, спецификация Java Virtual Machine Specification

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

В спецификации языка Java также указано

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

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

Итак

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

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

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

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

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


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

42
ответ дан 3 revs 17 August 2018 в 11:42
поделиться
  • 1
    Спасибо, что вы начали с обсуждения определений терминов. Это отличает ваш ответ от толпы и необходимо для правильного понимания. – Aaron 2 August 2017 в 15:39

Короче говоря, объекты 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 ++.

22
ответ дан 3 revs, 2 users 65% 17 August 2018 в 11:42
поделиться
  • 1
    Я думаю, что это очень близко к моему пониманию объекта Java и его ссылки. Объект в Java передается методу ссылочной копией (или псевдонимом). – MaxZoom 11 February 2015 в 06:58
29
ответ дан 3 revs, 2 users 71% 17 August 2018 в 11:42
поделиться

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

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

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

  • Студент : Мастер, означает ли это, что 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, а в начале она равна нулю.
  • В объекте # 2, сохраненном в памяти, создан новый объект Person, а переменной person присваивается ссылка на объект Person. То есть, его адрес. Скажем, 3bad086a.
  • Переменная person , удерживающая адрес объекта, передается функции в строке # 3.
  • В строке # 4 вы можете прослушивать звук молчания
  • Проверить комментарий на строке # 5
  • Локальная переменная метода - anotherReferenceToTheSamePersonObject - создана, а затем идет магическая строка # 6: переменная / ссылка person копируется по битам и передается в anotherReferenceToTheSamePersonObject внутри функции. Никаких новых экземпляров Person не создается. Оба « person » и « anotherReferenceToTheSamePersonObject « сохраняют одно и то же значение 3bad086a. Не пытайтесь это, но человек == anotherReferenceToTheSamePersonObject будет правдой. Обе переменные имеют ИДЕНТИФИКАЦИОННЫЕ КОПИИ ссылки, и оба они относятся к одному объекту Person, SAME Object on the Heap и NOT A COPY.

Изображение стоит тысячи слов:

Pass by Value [/g12]

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

Если вы этого не поняли, просто доверьтесь мне и помните, что лучше сказать, что Java проходит по значению. Ну, пройдем по эталонному значению. Ну, еще лучше pass-by-copy-of-the-variable-value! ;)

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

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

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

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


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


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

653
ответ дан 3 revs, 2 users 95% 17 August 2018 в 11:42
поделиться
  • 1
    Вы имеете в виду указатели? .. Если я правильно понял, в public void foo(Car car){ ... }, car является локальным для foo и содержит кучу объекта Object? Итак, если я изменил значение car на car = new Car(), он будет указывать на другой объект в куче? и если я изменил свойство свойства car на car.Color = "Red", объект в куче, указанный car, будет изменен. Кроме того, это то же самое в C #? Ответьте, пожалуйста! Благодаря! – dpp 25 February 2012 в 05:29
  • 2
    @domanokz Ты убиваешь меня, пожалуйста, не говори это слово снова! ;) Обратите внимание, что я мог бы ответить на этот вопрос, не сказав «ссылку». Это вопрос терминологии, и «p делает его хуже. К сожалению, у меня и шотландец разные взгляды. Я думаю, вы получили, как это работает на Java, теперь вы можете называть его передачей по значению, совместным использованием объектов, по-копиям-переменной-значения или без проблем придумывать что-то еще! Мне все равно, пока вы получили, как это работает, и что находится в переменной типа Object: просто адрес PO Box! ;) – Gevorg 25 February 2012 в 23:25
  • 3
    Похоже, вы просто передали ссылку ? Я собираюсь отстаивать тот факт, что Java по-прежнему является скопированным языком перекрестных ссылок. Тот факт, что это скопированная ссылка, не изменяет терминологию. И ССЫЛКИ по-прежнему указывают на тот же объект. Это аргумент пуриста ... – John Strickler 12 March 2014 в 19:38
  • 4
    Я предполагаю, что Java разработан с учетом указателей. В противном случае, почему NullPointerException существует? Тем не менее, за это замечательное объяснение, получение указателей просто усложнит – brain storm 20 August 2014 в 18:42
  • 5
    Итак, зайдите на теоретическую строку № 9 System.out.println(person.getName());, что будет отображаться? & Quot; Том & Quot; или "Джерри"? Это последнее, что поможет мне преодолеть эту путаницу. – TheBrenny 19 October 2014 в 13:20

Нет, он не проходит по ссылке.

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

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

50
ответ дан 3 revs, 3 users 82% 17 August 2018 в 11:42
поделиться

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

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

enter image description here [/g7]

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 с двумя различными ссылками , enter image description here [/g8]

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

В этой строке «pass-by-value» переходит в игру ...

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

Ссылки pnt1 и pnt2 передаются по значению сложному методу, что означает, что теперь ваши ссылки pnt1 и pnt2 имеют свои copies с именем arg1 и arg2. Так же pnt1 и arg1 указывают на тот же объект. (То же самое для pnt2 и arg2) enter image description here [/g9]

В методе tricky:

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

enter image description here [/g10]

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

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

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

enter image description here [/g11]

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

Итак, после выполнения метода tricky, когда вы вернетесь к main, у вас есть такая ситуация: enter image description here [/g12]

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

X1: 0         Y1: 0
X2: 0         Y2: 0
X1: 100       Y1: 100
X2: 0         Y2: 0
74
ответ дан 3 revs, 3 users 91% 17 August 2018 в 11:42
поделиться
  • 1
    В java, когда вы говорите & quot; В java все ссылается & quot; вы имеете в виду, что все объекты передаются по ссылке. Примитивные типы данных не передаются по ссылке. – Eric 22 October 2015 в 06:42
  • 2
    Я могу напечатать измененную стоимость в основном методе. в методе trickey добавьте следующий оператор arg1.x = 1; arg1.y = 1; arg2.x = 2; arg2.y = 2;, так как arg1 теперь держит pnt2 refrence и arg2, удерживая теперь ссылку pnt1, поэтому его печать X1: 2 Y1: 2 X2: 1 Y2: 1 – Shahid Ghafoor 20 December 2016 в 02:29

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

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.

49
ответ дан 4 revs, 2 users 76% 17 August 2018 в 11:42
поделиться
  • 1
    +1 для теста подкачки - вероятно, самый простой и относительный способ различать передачу по ссылке и передачи ссылки по значению . Iff, вы можете легко написать функцию swap(a, b), что (1) свопы a и b из POV вызывающего, (2) являются агностическими типами, насколько допускается статическая типизация (то есть использование его другим типом ничего не требует больше, чем изменение объявленных типов a и b), и (3) не требует, чтобы вызывающий ящик явно передавал указатель или имя, тогда язык поддерживает передачу по ссылке. – cHao 17 December 2013 в 23:24
  • 2
    «для примитивных типов данных вы будете работать с копией и для объектов, которые будут работать с копией ссылки на объекты». - отлично написано! – Raúl 24 November 2016 в 14:16

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

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

93
ответ дан 4 revs, 2 users 89% 17 August 2018 в 11:42
поделиться
  • 1
    Коллимально называется указателем. – Prof. Falken 9 February 2011 в 10:50
  • 2
    @Gevorg - Тогда что такое «NullPointerException»? – Hot Licks 22 September 2013 в 15:09
  • 3
    @Hot: К сожалению, названное исключение от Java доработало на понятной терминологии. Семантически эквивалентное исключение в c # называется NullReferenceException. – JacquesB 23 September 2013 в 15:08
  • 4
    Мне всегда казалось, что использование "ссылки" в терминологии Java - это аффектация, которая препятствует пониманию. – Hot Licks 23 September 2013 в 16:46
  • 5
    Я научился называть эти так называемые «указатели на объекты», как «обращение к объекту». Это уменьшило двусмысленность. – moronkreacionz 29 December 2015 в 22:36

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

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

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

Pass by ссылка (также называемая pass by address) означает, что копия адреса фактического параметра сохраняется.

Иногда 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, это просто пример).

first illustration [/g0]

new PassByValue().changeValue(t);

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

second illustration [/g1]

Если вы измените что-либо в функции с помощью ссылки 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, как показано ниже:

third illustration [/g2]

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

53
ответ дан 4 revs, 3 users 80% 17 August 2018 в 11:42
поделиться
  • 1
    Отличный ответ, ключ заявление: & Quot; При прохождении ссылочного т к функции не будет непосредственно передавать фактическое значение задания теста объекта, но это создаст копию т, а затем передать его в функцию & Quot; – pedram bashiri 4 May 2018 в 16:25

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


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

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");
    
    enter image description here [/g1]
  2. Со стороны метода указывается ссылка типа Foo с именем a и изначально назначена null.
    public static void changeReference(Foo a)
    
    enter image description here [/g2]
  3. Когда вы вызываете метод changeReference, ссылка a будет назначена объекту, который передается в качестве аргумента.
    changeReference(f);
    
    enter image description here [/g3]
  4. Объявление ссылки с именем b типа Foo и присвоение ее новому объекту типа Foo с атрибутом "b".
    Foo b = new Foo("b");
    
    enter image description here [/g4]
  5. a = b переназначает ссылку a NOT f объекту, чей его атрибут "b". enter image description here [/g5]
  6. Как вы называете метод modifyReference(Foo c), для объекта с атрибутом "f" создается и назначается ссылка c. enter image description here [/g6]
  7. c.setAttribute("c"); изменит атрибут объекта, на который указывает ссылка c, и это тот же объект, на который указывает ссылка f. enter image description here [/g7]

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

1395
ответ дан 4 revs, 3 users 88% 17 August 2018 в 11:42
поделиться
  • 1
  • 2
    @ Eng.Fouad Это приятное объяснение, но если a указывает на тот же объект, что и f (и никогда не получает свою собственную копию объекта f указывает на), любые изменения в объекте, выполненные с использованием a, должны измените f (так как они оба работают с одним и тем же объектом), поэтому в какой-то момент a должен получить свой собственный copy объекта f. – Mr D 15 July 2013 в 20:08
  • 3
    – Mike Braun 1 December 2013 в 15:02
  • 4
    – Evil Washing Machine 18 November 2014 в 12:34
  • 5
    Это лучшее объяснение, которое я нашел. Кстати, как насчет основной ситуации? Например, для аргумента требуется тип int, он все равно передает копию переменной int в аргумент? – allenwang 21 May 2016 в 12:38

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

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

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

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

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

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

563
ответ дан 4 revs, 4 users 40% 17 August 2018 в 11:42
поделиться
  • 1
    Поскольку значения примитивов неизменяемы (например, String), разница между этими двумя случаями не актуальна. – Paŭlo Ebermann 3 February 2011 в 02:23
  • 2
    В точку. Для всего, что вы можете сказать через наблюдаемое поведение JVM, примитивы могут передаваться по ссылке и могут жить в куче. Они этого не делают, но на самом деле это вообще не наблюдается. – Gravity 31 July 2011 в 05:50
  • 3
    примитивы неизменяемы? это что нового в Java 7? – Carlos Heuberger 22 August 2011 в 12:26
  • 4
    @CarlosHeuberger, «примитивы неизменяемы». Дело в том, что вы можете притворяться , что «примитивы» на самом деле (изменяемые) ссылки на неизменяемые объекты. – Aaron McDaid 30 July 2015 в 16:29
  • 5
    Указатели неизменяемы, примитивы вообще изменяемы. Строка также не примитивна, это объект. Более того, базовая структура String является изменяемым массивом. Единственная непреложная вещь в этом - это длина, которая является неотъемлемой природой массивов. – kingfrito_5005 12 August 2015 в 18:44

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

161
ответ дан 4 revs, 4 users 94% 17 August 2018 в 11:42
поделиться
  • 1
    +1 Я бы также добавил Dog **objPtrPtr к примеру C ++, таким образом мы можем изменить то, что указатель & quot; указывает на & quot ;. – Amro 2 July 2014 в 04:59
  • 2
    Это один из лучших ответов, которые я видел до сих пор. В основном это избегает аргумента несоответствующей семантики «ссылки на значение ссылочного». присутствует в другом месте и вместо этого обсуждает механику того, что на самом деле происходит. Я должен был предоставить большинство других «пропущенных значений». ответы -1 из-за их противоречивого или фактически ложного содержания, но вместо этого он получает +1. – Aaron 2 August 2017 в 15:32
28
ответ дан 5 revs 17 August 2018 в 11:42
поделиться
62
ответ дан 6 revs 17 August 2018 в 11:42
поделиться

Мне кажется, что спорить о «pass-by-reference vs pass-by-value» не очень полезно.

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

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

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

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

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

primitives on the stack [/g0]

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

Так же:

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

a b*7ch aint one! [/g1]

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

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

marx brothers [/g2]

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

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, так как адрес второй строки такой же, как и первый, новая String не создается и не выделяется новое пространство кучи, но новый идентификатор созданный в стеке. Затем мы вызываем shout(): создается новый стек стека и создается новый идентификатор name и назначается адрес уже существующей строки.

la da di da da da da [/g3]

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

199
ответ дан 6 revs, 4 users 97% 17 August 2018 в 11:42
поделиться
  • 1
    Тем не менее, вам следовало бы выполнить более сложный пример, когда функция, как представляется, изменяет переменную, на адрес которой имеется ссылка. – Brian Peterson 1 November 2013 в 08:53
  • 2
    Люди не «танцуют вокруг настоящей проблемы», стека против кучи, потому что это not реальная проблема. В лучшем случае это деталь реализации, и в худшем случае это совершенно неправильно. (Вполне возможно, что объекты будут находиться в стеке, google & quot; анализ анализа & quot ;, и огромное количество объектов содержит примитивы, которые, вероятно, не живут в стеке.) Реальная проблема: i> точно разность между ссылочными типами и типами значений - в частности, что значение переменной ссылочного типа является ссылкой, а не объектом, к которому она относится. – cHao 18 December 2013 в 06:48
  • 3
    Это «деталь реализации». в том, что Java никогда не требуется, чтобы на самом деле показать вам, где находится объект в памяти, и на самом деле кажется, что он избегает утечки этой информации. Он может помещать объект в стек, и вы никогда не узнаете. Если вам все равно, вы фокусируетесь на неправильном - и в этом случае это означает игнорирование реальной проблемы. – cHao 18 December 2013 в 16:38
  • 4
    И в любом случае, «примитивы идут в стек», это неверно. Примитивные локальные переменные идут в стек. (Если они не были оптимизированы, конечно.) Но тогда так делают локальные ссылочные переменные . И примитивные члены, определенные внутри объекта, живут везде, где объект живет. – cHao 18 December 2013 в 16:55
  • 5
    Согласитесь с комментариями здесь. Стек / куча является побочным вопросом и не имеет значения. Некоторые переменные могут находиться в стеке, некоторые из них находятся в статической памяти (статические переменные), а в куче - много (все переменные-члены объекта). НЕТ этих переменных можно передать по ссылке: из вызываемого метода НИКОГДА не возможно изменить значение переменной, передаваемой в качестве аргумента. Поэтому в Java нет пропущенных ссылок. – fishinear 2 March 2014 в 17:37

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

135
ответ дан Jörg W Mittag 17 August 2018 в 11:42
поделиться
  • 1
    Мне нравится это различие в номенклатуре. К сожалению, Java поддерживает вызов путем совместного использования для объектов, но не вызывает по значению (как и C ++). Java поддерживает вызов по значению только для примитивных типов данных, а не для составных типов данных. – Derek Mahar 8 September 2010 в 15:16
  • 2
    Я действительно не думаю, что нам нужен дополнительный термин - это просто пропускная способность для определенного типа значения. Добавил бы & quot; вызов примитивным & quot; добавить какие-либо разъяснения? – Scott Stanchfield 25 October 2010 в 21:03
  • 3
  • 4
    Таким образом, я могу передавать по ссылке, разделяя некоторый глобальный объект контекста или даже передавая объект контекста, который содержит другие ссылки? Я по-прежнему передаю по значению, но по крайней мере у меня есть доступ к ссылкам I can и они указывают на что-то еще. – YoYo 8 January 2016 в 01:14

Вы никогда не можете передавать по ссылке в 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.

43
ответ дан Jared Oberhaus 17 August 2018 в 11:42
поделиться

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

145
ответ дан John Channing 17 August 2018 в 11:42
поделиться

Как многие люди говорили об этом раньше, Java всегда имеет значение pass-by-value

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

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 будет меняться только в локальной области, а не за пределами этого метода.

30
ответ дан pek 17 August 2018 в 11:42
поделиться

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

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

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

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

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

23
ответ дан Rusty Shackleford 17 August 2018 в 11:42
поделиться
  • 1
    +1. Поддержка C поддерживает , обрабатывает ссылки (которые C называет указатели ) как значения первого класса, а < i> then , передавая их по значению . – Jörg W Mittag 7 September 2010 в 23:02
  • 2
    Да, в C вы можете создавать указатели не только на объекты, но и на произвольные переменные - чтобы вы могли легко имитировать «вызов по ссылке», любой переменной. В Java это работает только для переменных, у которых есть окружающий объект, который вы можете дать. – Paŭlo Ebermann 3 February 2011 в 02:27

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

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

280
ответ дан ScArcher2 17 August 2018 в 11:42
поделиться
  • 1
    Но то, что продолжает повторяться, «вы не можете изменить значение объектов, переданных в аргументах». явно ложно. Возможно, вы не сможете заставить их ссылаться на другой объект, но вы можете изменить их содержимое, вызвав их методы. ИМО означает, что вы теряете все преимущества ссылок и не получаете никаких дополнительных гарантий. – Timmmm 24 July 2011 в 20:13
  • 2
    Я никогда не говорил «вы не можете изменить значение объектов, переданных в аргументах». Я скажу: «Вы не можете изменить значение ссылки на объект, переданное как аргумент метода», что является истинным утверждением о языке Java. Очевидно, вы можете изменить состояние объекта (если оно не является неизменным). – ScArcher2 1 August 2011 в 15:19
  • 3
    Имейте в виду, что вы не можете передавать объекты в java; объекты остаются на куче. Указатели к объектам могут быть переданы (которые копируются в стек стека для вызываемого метода). Таким образом, вы никогда не меняете переданное значение (указатель), но вы можете следовать за ним и изменять предмет в куче, на которую он указывает. Это пропускная стоимость. – Scott Stanchfield 27 January 2012 в 00:17
  • 4
    Похоже, вы просто передали ссылку ? Я собираюсь отстаивать тот факт, что Java по-прежнему является скопированным языком перекрестных ссылок. Тот факт, что это скопированная ссылка, не изменяет терминологию. И ССЫЛКИ по-прежнему указывают на тот же объект. Это аргумент пуриста ... – John Strickler 12 March 2014 в 19:38
  • 5
    Java не передает объект, он передает значение указателя на объект. Это создает новый указатель на эту ячейку памяти исходного объекта в новой переменной. Если вы измените значение (адрес памяти, на которое оно указывает) этой переменной указателя в методе, то исходный указатель, используемый в вызывающем методе, остается неизменным. Если вы вызываете параметр ссылкой, то факт, что он является копией исходной ссылки, а не самой исходной ссылкой, так что есть теперь две ссылки на объект, означает, что она является проходом -стоимость – theferrit32 19 November 2014 в 17:38

Позвольте мне объяснить свое понимание с помощью четырех примеров. Java является pass-by-value, а не pass-by-reference

/ **

Pass By Value

В 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:

/ ** * * Pass By Value * * /

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

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

    }

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

Результат

output : output
value : Nikhil
valueflag : false

Пример 3:

/ ** У этого «Pass By Value» есть ощущение «Pass By Reference»

Некоторые говорят, что примитивные типы и «String» являются «pass by value», а объекты «проходят» по ссылке '.

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

* /

public class PassByValueObjectCase1 {

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

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

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

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

Результат

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

Пример 4:

/ **

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

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

* /

public class PassByValueObjectCase2 {

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

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

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

}

Результат

output : output
student : Student [id=10, name=Nikhil]
46
ответ дан 2 revs 17 August 2018 в 11:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: