Вы предоставили выдержки из контекста diff, который показывает обе строки, которые одинаковы в обоих файлах и строках, которые были изменены. Однако выбранные выдержки не показывают никаких измененных строк. (Этим будут предшествовать символы - или + в зависимости от того, удаляются или добавляются они.)
@@ -15,4 +22,6 @@ означает, что 4 линии, начинающиеся с строки 15 в старый файл изменен (или не изменен, но показан как контекст) и соответствует строкам 6, начинающимся с строки 22 в новом файле. (Самый простой и наиболее распространенный способ для этого - количество строк, добавленных в новый файл, превышает количество строк, удаленных в новом файле, на 7, так что начало работы в строке 15 в старом файле начинается в строке 22 в новом файле, до применения изменений, которые должны быть указаны.)
Поскольку это контекст diff, он предоставляет некоторые строки для контекста, которые не указывают изменения. Это полезно, чтобы люди могли редактировать файлы (разработчики / сопровождающие, когда это исходный код, как в этом случае), чтобы знать, что происходит, сбрасывая diff. Но у него есть другая полезная цель - во многих случаях применить diff, созданный против одной версии файла, против другой версии того же файла, при условии, что он не изменит те же самые строки, которые уже были изменены (т. е. были изменены после того, как был создан diff, но до его применения).
Предположительно присутствуют следующие строки в контексте в diff, поскольку произошли изменения незадолго до них (так что они представлены в контексте context diff a change):
if __name__ == "__main__": myparams = {"server":"mpilgrim", \В то время как эти строки предположительно присутствуют, как контекст, в diff, потому что вскоре произойдет изменение после них (поэтому они представляют собой контекст, предоставленный перед изменением):
"pwd":"secret" \ }Эти строки, по-видимому, недостаточно близки к перед изменением , указанным в diff, который будет включен как контекст:
"database":"master", \ "uid":"sa", \Вот почему они выглядят так, как будто их нет в разнице. Их действительно не хватает, потому что diff не должен показывать вам весь файл. Возьмите домашнее сообщение обо всем этом, что их отсутствие происходит не потому, что diff указывает, что они будут удалены. Это, конечно, не указывает, что - если бы это было так, то это должно было бы включать их (с знаками - перед ними, чтобы указать их удаление).
(я говорю, not не потому, что существует большая вероятность того, что это не то, что происходит, а потому, что, пока утилита diff создаст diff с указанными числами before и , включит контекстные строки , вы можете, если вам нужно было вручную создать или изменить diff, чтобы в некоторых местах было больше или меньше линий контекста, чем в других, и это все равно было бы действительным различием при условии, что при необходимости номера в @@ линиях, где они были изменены match.)
Для получения дополнительной информации о diff (утилиты diff, patch, diff3 и sdiff, а также формат diff / patch), см. документацию по GNU diff. В частности, вас может заинтересовать раздел, посвященный унифицированному формату.
Я просто заметил, что вы ссылались на мою статью.
Java Spec говорит, что все в Java является передачей по значению. [] D2]
Ключом к пониманию этого является то, что что-то вроде
Dog myDog;
не является Собакой; на самом деле это указатель на Собака.
Что это значит, когда у вас есть
Dog myDog = new Dog("Rover");
foo(myDog);
, вы по существу передаете не созданного Dog ссылается на метод foo.
(я говорю, по сути, потому, что указатели Java не являются прямыми адресами, но проще всего их так думать)
Предположим, Объект Dog находится по адресу памяти 42. Это означает, что мы передаем метод 42.
, если метод был определен как
public void foo(Dog someDog) {
someDog.setName("Max"); // AAA
someDog = new Dog("Fifi"); // BBB
someDog.setName("Rowlf"); // CCC
}
, давайте посмотрим, что происходит.
параметр someDog установлен в значение 42 в строке «AAA» someDog, после чего он Dog указывает на (объект Dog по адресу 42), что Dog ( один по адресу 42) просят сменить свое имя на Макс в строке «BBB», создается новый Dog. Предположим, что он находится по адресу 74, мы назначаем параметр someDog равным 74 в строке «CCC». Некоторый Dog следует за Dog, который указывает (объект Dog по адресу 74), что Dog (тот, что по адресу 74) просят изменить свое имя на Rowlf, тогда мы вернем. Теперь давайте подумаем о том, что происходит вне метода:
Изменился ли myDog?
Есть ключ.
Имея в виду, что myDog является Изменено myDog? , а не фактическое Dog, ответ НЕТ. myDog все еще имеет значение 42; он все еще указывает на оригинал Dog (но обратите внимание, что из-за строки «AAA» его имя теперь «Макс» - все тот же Dog, значение myDog не изменилось.)
Совершенно верно следить за адресом и изменять то, что в конце его; это не изменяет переменную.
Java работает точно так же, как C. Вы можете назначить указатель, передать указатель на метод, следовать указателю в методе и изменить данные, на которые указали. Тем не менее, вы не можете изменить, где находится этот указатель.
В C ++, Ada, Pascal и других языках, поддерживающих pass-by-reference, вы можете фактически изменить переданную переменную.
Если Java имела семантику pass-by-reference, метод foo, который мы определили выше, изменился бы там, где myDog указывал, когда он назначил someDog в строке BBB.
Подумайте о контрольных параметрах как как псевдонимы для переданной переменной. Когда этот псевдоним назначается, то и переменная, которая была передана.
Java - это вызов по значению.
Как это работает.
Вы всегда передаете копию бит значения ссылки! Если это примитивный тип данных, эти биты содержат значение самого примитивного типа данных. Поэтому, если мы изменим значение заголовка внутри метода, то оно не отражает изменения вне. Если это тип данных объекта, например Foo foo = new Foo (), тогда в этом случае копия адреса объекта проходит как ярлык файла, предположим, что у нас есть текстовый файл abc.txt на C: \ desktop и предположим, что мы делаем ярлык тот же файл и поместите это внутри C: \ desktop \ abc-shortcut, поэтому, когда вы получаете доступ к файлу из C: \ desktop \ abc.txt и пишите 'Stack Overflow' и закрываете файл, и снова вы открываете файл из ярлыка, тогда вы write 'является крупнейшим онлайн-сообществом для программистов, чтобы узнать, что тогда полное изменение файла будет «Stack Overflow - это самое большое онлайн-сообщество для программистов, чтобы учиться», что означает, что не имеет значения, откуда вы открываете файл, каждый раз, когда мы обращались к нему тот же файл, здесь мы можем считать Foo в качестве файла и предположим, что foo хранится на адресе 123hd7h (исходный адрес, например C: \ desktop \ abc.txt) и 234jdid (скопированный адрес, такой как C: \ desktop \ abc-shortcut, который фактически содержит исходный адрес файла внутри). Поэтому для лучшего понимания создайте ярлык и почувствуйте ... [!d 2]Я создал поток, посвященный этим типам вопросов для любых языков программирования здесь.
здесь . Вот краткое резюме:
Java передает его параметры по значению «по значению» - это единственный способ в java передать параметр методу, используя методы из объекта, заданного как параметр, изменит объект как ссылки указывают на исходные объекты. (если этот метод сам изменяет некоторые значения)Различие, или, может быть, только то, как я помню, поскольку я имел такое же впечатление, что и исходный плакат: Java всегда проходит по значению. Все объекты (в Java, все, кроме примитивов) в Java - это ссылки. Эти ссылки передаются по значению.
Java передает параметры по VALUE и по значению ТОЛЬКО.
ТОЛЬКО
Для тех, кто приходит из C #: нет параметра «out». Для тех, кто прибывает из PASCAL: нет параметра «var».Это означает, что вы не можете изменить ссылку из самого объекта, но вы всегда можете изменить свойства объекта.
Обходным путем является использование параметра StringBuilder вместо String , И вы всегда можете использовать массивы!
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();
}
В принципе, переназначение параметров объекта не влияет на аргумент, например,
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.
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")), .
Я думал, что внес свой ответ, чтобы добавить более подробную информацию из Спецификаций.
Во-первых, В чем разница между передачей по ссылке или передачей по значению?
reference означает, что параметр вызываемых функций будет таким же, как переданный аргумент вызывающих (не значение, а идентификатор - сама переменная). Передача по значению означает, что параметр вызываемых функций будет копией переданного аргумента вызывающих.Или из wikipedia, В чем разница между передачей по ссылке или передачей по значению?
Передача по ссылке означает параметр вызываемых функций будет таким же, как переданный аргумент вызывающих (а не значение, а идентификатор - сама переменная).
При оценке по принципу «по вызову» (также называемой «пересылкой») функция получает неявную ссылку на переменную, используемую как аргумент, а не копию ее значения , Это обычно означает, что функция может изменять (т. Е. Присваивать) переменную, используемую как аргумент, - то, что будет видно ее вызывающей стороне.
В вызове по значению вычисляется выражение аргумента, а результирующее значение привязано к соответствующей переменной в функции [...]. Если функция или процедура могут назначать значения своим параметрам, назначается только ее локальная копия [...].И по вопросу о прохождении значения
В вызове по-умолчанию вычисляется выражение аргумента, и результирующее значение привязывается к соответствующей переменной в функции [...]. Если функция или процедура могут назначать значения своим параметрам, назначается только ее локальная копия [...].
Во-вторых, нам нужно знать, что использует Java в своих методах , Спецификация языка Java указывает на
Когда вызывается метод или конструктор (§15.12), значения фактических выражений аргументов инициализируют вновь созданные переменные параметра, каждый из объявленного типа, перед выполнением тела метод или конструктор.
Таким образом, он присваивает (или связывает) значение аргумента соответствующей переменной параметра.
Существует три типа ссылочных типов: типы классов, типы массивов и типы интерфейсов. Их значения - это ссылки на динамически созданные экземпляры классов, массивы или экземпляры классов или массивы, реализующие интерфейсы, соответственно.Каково значение аргумента?
Существует три типа ссылочных типов: типы классов, типы массивов и типы интерфейсов. Их значения - это ссылки на динамически созданные экземпляры классов, массивы или экземпляры классов или массивы, которые реализуют интерфейсы соответственно.
Давайте рассмотрим ссылочные типы, на тему прохода -value states
Спецификация языка Java также указывает
public void method (String param) {}
...
String var = new String("ref");
method(var);
method(var.toString());
method(new String("ref"));
. Опорные значения (часто просто ссылки) являются указателями на эти объекты , и специальная нулевая ссылка, которая ссылается на отсутствие объекта.
Значение аргумента (некоторого ссылочного типа) является указателем на объект. Обратите внимание, что переменная, вызов метода с типом возвращаемого типа ссылочного типа и выражение создания экземпляра (new ...) разрешают все значения ссылочного типа.
Это обычно означает, что функция может изменять (т. е. присваивать) переменную, используемую как аргумент, что будет видно ее вызывающей стороне.Итак,
все связывают значение ссылки с экземпляром String с вновь созданным параметром метода, param. Это именно то, что описывает определение pass-by-value. Таким образом, значения фактических выражений аргументов инициализируют вновь созданные переменные параметра .
Чтобы сделать длинную историю, объекты 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 ++.
Я всегда думаю об этом как «проход по копии». Это копия значения, будь она примитивной или справочной. Если это примитив, это копия битов, которые являются значением, и если это объект, то это копия ссылки.
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Примитивные классы-оболочки и строки неизменяемы, поэтому любой пример с использованием этих типов не будет работать так же, как другие типы / объекты.
Это даст вам некоторое представление о том, как Java действительно работает до такой степени, что в следующем обсуждении о передаче Java по ссылке или передаче по значению вы просто будете улыбаться: -)
Шаг один, пожалуйста, удалите из вашего разума это слово, которое начинается с «p» «_ _ _ _ _ _ _», особенно если вы исходите из других языков программирования. Java и «p» не могут быть записаны в одной книге, форуме или даже в txt.
Шаг два помнит, что при передаче объекта в метод, с которым вы передаете ссылку Object, а не сам объект .
Студент: Мастер, означает ли это, что Java является передачей по ссылке? Мастер: Grasshopper, No.Теперь подумайте о том, что ссылка / переменная объекта имеет /:
Переменная содержит биты, которые сообщают JVM, как добраться до ссылочного объекта в память (куча). При передаче аргументов методу вы НЕ передаете ссылочную переменную, а копию битов в ссылочной переменной. Что-то вроде этого: 3bad086a. 3bad086a представляет способ доступа к переданному объекту. Таким образом, вы просто передаете 3bad086a, что это значение ссылки. Вы передаете значение ссылки, а не саму ссылку (а не объект). Это значение фактически КОПИРОВАНО и передается методу.В следующем (пожалуйста, не пытайтесь скомпилировать / выполнить это ...):
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. }
Что происходит?
Студент : Master, означает ли это, что Java является передачей по ссылке? Новый объект Person создается в строке # 2, сохранен в памяти, а переменной Student дается ссылка на объект Person. То есть, его адрес. Скажем, 3bad086a. Мастер: Grasshopper, No. В строке # 4 вы можете прослушать звук тишины. Отметьте комментарий на строке # 5. Будет создана локальная переменная метода -anotherReferenceToTheSamePersonObject- и затем появится волшебство в строке # 6 : Переменная / ссылочная запись копируется по битам и передается в другую функциюReferenceToTheSamePersonObject внутри функции. Никаких новых экземпляров Person не создается. И «person», и «anotherReferenceToTheSamePersonObject» имеют одинаковое значение 3bad086a. Не пытайтесь это, но человек == anotherReferenceToTheSamePersonObject будет правдой. Обе переменные имеют ИДЕНТИФИКАЦИОННЫЕ КОПИИ ссылки, и оба они относятся к одному объекту Person, SAME Object on the Heap и NOT A COPY.Изображение стоит тысячи слов:
Это даст вам некоторое представление о том, как Java действительно работает до такой степени, что в следующем обсуждение о передаче Java по ссылке или передаче по значению, вы просто улыбаетесь: -)
Если вы этого не поняли, просто доверьтесь мне и помните, что лучше сказать, что Java перейдите по значению. Ну, пройдем по эталонному значению. О, хорошо, еще лучше - это пропускная способность-переменная-значение! ;)
Теперь не стесняйтесь меня ненавидеть, но обратите внимание, что, учитывая эту , Java передается по значению при обсуждении аргументов метода.
Вы всегда передаете копию из битов значения ссылки!
Новый объект Person создается в строке # 2, сохранен в памяти, а переменной Student задана ссылка к объекту Person. То есть, его адрес. Скажем, 3bad086a. Если это объект, биты будут содержать значение адреса, сообщающего JVM, как добраться до объекта. Java - это пропускная способность, потому что внутри метода вы можете изменить ссылочный объект столько, сколько хотите, но как бы вы ни старались, вы никогда не сможете изменить переданную переменную, которая будет поддерживать ссылаясь (не p _ _ _ _ _ _ _) тот же объект, независимо от того, что!Java является передачей по значению, потому что внутри метода вы можете изменить ссылочный объект столько, сколько хотите, но как бы вы ни старались, вы никогда не сможете (no p _ _ _ _ _ _ _) тот же объект, независимо от того, что!
Функция changeName выше никогда не сможет изменить фактическое содержимое (битовые значения) переданной ссылки. В другом слове changeName не может заставить Person person ссылаться на другой Object.
Нет, он не проходит по ссылке.
Java передается по значению в соответствии со спецификацией языка Java:
При вызове метода или конструктора (§15.12) значения фактических выражений аргументов инициализируют вновь созданные переменные параметра, каждый из объявленного типа, перед выполнением тела метода или конструктора. Идентификатор, который появляется в DeclaratorId, может использоваться как простое имя в теле метода или конструктора для обозначения формального параметра.В java все ссылается, поэтому, когда у вас есть что-то вроде: Point pnt1 = new Point(0,0); Java делает следующее:
Создает новый объект Point Создает новую ссылку Point и инициализирует эту ссылку на точку (см.) ранее созданный объект Point. Отсюда, через жизнь объекта 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 с двумя связанными ссылками. [!d8]
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
Java не передает аргументы метода по ссылке;
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;
[!d22]
Далее в методе tricky
Point temp = arg1;
arg1 = arg2;
arg2 = temp;
Здесь вы сначала создаете новую ссылку temp Point, которая будет указывает в том же месте, что и arg1. Затем вы перемещаете ссылку arg1, чтобы указать на то же место, что и arg2. Наконец, arg2 будет указывать на то же место, что и temp.
Отсюда сфера применения метода tricky исчезла, и у вас больше нет доступа к ссылки: arg1, arg2, temp. передано значением
Итак, после выполнения метода tricky, когда вы вернетесь к main, у вас есть такая ситуация: [!d32]
Итак, теперь полное выполнение программы будет:
X1: 0 Y1: 0
X2: 0 Y2: 0
X1: 100 Y1: 100
X2: 0 Y2: 0
Насколько я знаю, 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.
Суть дела в том, что ссылка слова в выражении «передать по ссылке» означает нечто совершенно отличное от обычного значения ссылки на слово в Java.
Обычно в Java ссылка означает ссылку на объект. Но технические термины reference из теории языка программирования говорят о ссылке на ячейку памяти, в которой находится переменная, что совершенно другое.
Java всегда проходит по значению, а не по ссылке
. Прежде всего, нам нужно понять, что проходит по значению и передается по ссылке.
Java всегда передается по значению, а не по ссылке .
Передача по ссылке (также называемая 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 равно 0x100234 (мы не знаем фактического внутреннего значения JVM, это просто пример).
new PassByValue().changeValue(t);
При передаче ссылка т к функции не будут непосредственно передать фактическое значение задания теста объекта, но это создаст копию т, а затем передать его в функцию. Так как это Передача по ссылке (также называемая pass by address) означает, что копия адреса фактического параметра сохраняется , она передает копию переменной, а не фактическую ссылку на нее. Поскольку мы сказали, что значение t было 0x100234, оба t и f будут иметь одинаковое значение и, следовательно, они будут указывать на один и тот же объект.
[!d13]
Если вы измените что-либо в функции с помощью ссылки 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, как показано ниже:
Надеюсь, это поможет.
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");
}
}
Я объясню это в шаги:
Объявление ссылки с именем f типа Foo и присвоение ее новому объекту типа Foo с атрибутом "f".Foo f = new Foo("f");
Со стороны метода указывается ссылка типа Foo с именем a и первоначально назначена null. public static void changeReference(Foo a)
Когда вы вызываете метод changeReference, ссылка a будет назначена объекту, который передается в качестве аргумента. changeReference(f);
Объявление ссылки с именем b типа Foo и присвоение ее новому объекту типа Foo с атрибутом "b". Foo b = new Foo("b");
a = b переназначает ссылку a NOT f объекту, чей его атрибут "b". Когда вы вызываете метод modifyReference(Foo c), для объекта с атрибутом "f" создается и назначается ссылка c. c.setAttribute("c"); изменит атрибут объекта, на который указывает ссылка c, и тот же объект, на который указывает ссылка f. Надеюсь, теперь вы понимаете, как объекты передачи в качестве аргументов работают в Java:)
Java всегда проходит по значению, без каких-либо исключений.
Итак, как же все могут быть смущены этим и считают, что Java проходит по ссылке или думает, что они пример Java, действующий как пропуск по ссылке? Ключевым моментом является то, что Java когда-либо обеспечивает прямой доступ к значениям самих объектов при любых обстоятельствах. Единственный доступ к объектам - это ссылка на этот объект. Поскольку объекты Java всегда обращаются через ссылку, а не напрямую, обычно говорят о том, что поля, переменные и аргументы метода являются объектами, когда педантично они являются только ссылками на объекты. Путаница проистекает из этого (строго говоря, неправильного) изменения в номенклатуре.
Итак, при вызове метода
Для примитивных аргументов (int, long и т. Д.), , пропуск по значению является фактическим значением примитива (например, 3). Для объектов пропуск по значению - это значение ссылки на объект.Итак, если у вас есть doSomething(foo) и public void doSomething(Foo foo) { .. }, два объекта Foos скопировали объекты сами , которые указывают на те же объекты.
Естественно, проходя мимо Значение ссылки на объект очень похоже (и на практике неотличимо) от передачи объекта по ссылке.
Чтобы показать контраст, сравните следующие фрагменты 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 имеет только два типа передачи: по значению для встроенных типов и по значению указатель на типы объектов.
В Java передаются только ссылки и передаются по значению:
Аргументы Java: В Java передаются только ссылки и передаются по значению: (ссылка копируется, когда используемый в методе):
В случае примитивных типов поведение Java простое: значение копируется в другом экземпляре примитивного типа.
В случае объектов это то же: Объектные переменные - это указатели (ведра), содержащие только адрес объекта, который был создан с использованием «нового» ключевого слова, и скопированы как примитивные типы.
Поведение может отличаться от примитивных типов: поскольку скопированная объектная переменная содержит один и тот же адрес (к одному и тому же объекту). адрес объекта все еще может быть изменен в рамках метода и позже доступен для доступа снаружи, что дает иллюзию того, что сам объект (содержащий) был передан по ссылке.
Объекты «String», кажется, идеальный контрастный пример для городской легенды, говорящий, что «Объекты переданы по ссылке»:
По сути, в рамках метода вы никогда не будете чтобы обновить значение String, переданное как аргумент:
Объект String, содержит символы с объявленным массивом идеальным встречным примером , который не может быть изменен. Только адрес объекта может быть заменен другим, используя «новый». Использование «нового» для обновления переменной не позволит объекту получить доступ извне, поскольку переменная была первоначально передана по значению и скопирована.
Мне кажется, что спорить о «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;
приводит к этому:
Когда вы объявляете и создаете экземпляр объекта. Фактический объект переходит в кучу. Что происходит в стеке? Адрес объекта в куче. Программисты на С ++ назвали бы это указателем, но некоторые разработчики Java против слова «указатель». Без разницы. Просто знайте, что адрес объекта идет в стек.
Так же:
int problems = 99;
String name = "Jay-Z";
[!d6]
Массив объект, поэтому он также попадает в кучу. А как насчет объектов в массиве? Они получают свое собственное пространство кучи, и адрес каждого объекта попадает внутрь массива.
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, так как адрес второй строки такой же, как и первый, новая String не создается и не выделяется новое пространство кучи, но новый идентификатор созданный в стеке. Затем мы вызываем shout(): создается новый стек стека и создается новый идентификатор name и назначается адрес уже существующей строки.
[!d13]
Итак, значение, ссылка? Вы говорите «картофель».
Не могу поверить, что никто еще не упомянул Барбару Лисков. Когда она разработала CLU в 1974 году, она столкнулась с этой же проблемой терминологии, и она придумала термин «вызов» путем совместного использования (также называемого вызовом путем совместного использования объектов и вызова по объекту) для этого конкретного случая «вызов по значению, где значение ссылка ".
Вы никогда не можете передавать по ссылке в 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.
Java передает ссылки на объекты по значению.
Как уже многие люди говорили об этом раньше, Java всегда имеет значение pass-by-value
Вот еще один пример, который поможет вам понять разницу ( 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 будет меняться только в локальной области, но не вне этого метода.
Несколько поправок к некоторым сообщениям.
C не поддерживает передачу по ссылке. Он ВСЕГДА проходит по значению.
Не имеет значения, что такое значение в Java: примитивный или адрес (примерно) объекта, он ВСЕГДА прошел мимо value.
Если объект Java «ведет себя» подобно тому, как он передается по ссылке, это свойство изменчивости и не имеет абсолютно никакого отношения к передающим механизмам.
Я не почему это так запутанно, возможно, потому, что так много «программистов» Java официально не обучены и, следовательно, не понимают, что происходит в памяти?
Java передает ссылки по значению.
Таким образом, вы не можете изменить ссылку, которая будет передана.
Позвольте мне объяснить свое понимание с помощью четырех примеров. 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";
}
}
Пример 1: [ ! d6]
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";
}
}
Пример 2:
output : output
value : Nikhil
valueflag : false
Пример 3:
/ ** У этого «Pass By Value» есть ощущение «Pass By Reference»
Некоторые люди например, примитивные типы и «String» являются «pass by value», а объекты «передаются по ссылке».
Но из этого примера мы можем понять, что это infact pass by value only, имея в виду, что здесь мы передаем ссылку как значение. т.е.: ссылка передается по значению. Вот почему они могут меняться, и все же это верно после локального масштаба. Но мы не можем изменить фактическую ссылку за пределами исходной области. что это означает, показано в следующем примере 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";
}
}
Пример 3:
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";
}
}
Пример 4:
output : output
student : Student [id=10, name=Nikhil]