I always thought Java uses pass-by-reference. However, I read a blog post which claims that Java uses pass-by-value. I don't think I understand the distinction the author is making.
Java is pass by value according to the Java Language Specification:
When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables, each of the declared type, before execution of the body of the method or constructor. The Identifier that appears in the DeclaratorId may be used as a simple name in the body of the method or constructor to refer to the formal parameter.
public class PassByValueString {
public static void main(String[] args) {
new PassByValueString().caller();
}
public void caller() {
String value = "Nikhil";
boolean valueflag = false;
String output = method(value, valueflag);
/*
* 'output' is insignificant in this example. we are more interested in
* 'value' and 'valueflag'
*/
System.out.println("output : " + output);
System.out.println("value : " + value);
System.out.println("valueflag : " + valueflag);
}
public String method(String value, boolean valueflag) {
value = "Anand";
valueflag = true;
return "output";
}
}
结果
output : output
value : Nikhil
valueflag : false
示例2:
/**
*
*按价值通过
*
*/
public class PassByValueNewString {
public static void main(String[] args) {
new PassByValueNewString().caller();
}
public void caller() {
String value = new String("Nikhil");
boolean valueflag = false;
String output = method(value, valueflag);
/*
* 'output' is insignificant in this example. we are more interested in
* 'value' and 'valueflag'
*/
System.out.println("output : " + output);
System.out.println("value : " + value);
System.out.println("valueflag : " + valueflag);
}
public String method(String value, boolean valueflag) {
value = "Anand";
valueflag = true;
return "output";
}
}
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";
}
}
Let me try to explain my understanding with the help of four examples. Java is pass-by-value, and not pass-by-reference
/**
Pass By Value
In Java, all parameters are passed by value, i.e. assigning a method argument is not visible to the caller.
*/
Example 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";
}
}
Result
output : output
value : Nikhil
valueflag : false
Example 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";
}
}
Result
output : output
value : Nikhil
valueflag : false
Example 3:
/**
This 'Pass By Value has a feeling of 'Pass By Reference'
Some people say primitive types and 'String' are 'pass by value'
and objects are 'pass by reference'.
But from this example, we can understand that it is infact pass by value only,
keeping in mind that here we are passing the reference as the value.
ie: reference is passed by value.
That's why are able to change and still it holds true after the local scope.
But we cannot change the actual reference outside the original scope.
what that means is demonstrated by next example of 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";
}
}
In addition to what was mentioned in Example3 (PassByValueObjectCase1.java), we cannot change the actual reference outside the original scope."
Note: I am not pasting the code for private class Student. The class definition for Student is same as Example3.
*/
public class PassByValueObjectCase2 {
public static void main(String[] args) {
new PassByValueObjectCase2().caller();
}
public void caller() {
// student has the actual reference to a Student object created
// can we change this actual reference outside the local scope? Let's see
Student student = new Student(10, "Nikhil");
String output = method(student);
/*
* 'output' is insignificant in this example. we are more interested in
* 'student'
*/
System.out.println("output : " + output);
System.out.println("student : " + student); // Will it print Nikhil or Anand?
}
public String method(Student student) {
student = new Student(20, "Anand");
return "output";
}
}
In call-by-reference evaluation (also referred to as
pass-by-reference), a function receives an implicit reference to a
variable used as argument, rather than a copy of its value. This
typically means that the function can modify (i.e. assign to) the
variable used as argument—something that will be seen by its caller.
In call-by-value, the argument expression is evaluated, and the
resulting value is bound to the corresponding variable in the function [...].
If the function or procedure is able to assign values to its
parameters, only its local copy is assigned [...].
When the method or constructor is invoked (§15.12), the values of the
actual argument expressions initialize newly created parameter
variables, each of the declared type, before execution of the body of
the method or constructor.
So it assigns (or binds) the value of the argument to the corresponding parameter variable.
There are three kinds of reference types: class types, array types,
and interface types. Their values are references to dynamically
created class instances, arrays, or class instances or arrays that
implement interfaces, respectively.
The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object.
The value of an argument (of some reference type) is a pointer to an object. Note that a variable, an invocation of a method with a reference type return type, and an instance creation expression (new ...) all resolve to a reference type value.
So
public void method (String param) {}
...
String variable = new String("ref");
method(variable);
method(variable.toString());
method(new String("ref"));
all bind the value of a reference to a String instance to the method's newly created parameter, param. This is exactly what the definition of pass-by-value describes. As such, Java is pass-by-value.
The fact that you can follow the reference to invoke a method or access a field of the referenced object is completely irrelevant to the conversation. The definition of pass-by-reference was
This typically means that the function can modify (i.e. assign to) the
variable used as argument—something that will be seen by its caller.
In Java, modifying the variable means reassigning it. In Java, if you reassigned the variable within the method, it would go unnoticed to the caller. Modifying the object referenced by the variable is a different concept entirely.
Primitive values are also defined in the Java Virtual Machine Specification, here. The value of the type is the corresponding integral or floating point value, encoded appropriately (8, 16, 32, 64, etc. bits).
You can never pass by reference in Java, and one of the ways that is obvious is when you want to return more than one value from a method call. Consider the following bit of code in C++:
void getValues(int& arg1, int& arg2) {
arg1 = 1;
arg2 = 2;
}
void caller() {
int x;
int y;
getValues(x, y);
cout << "Result: " << x << " " << y << endl;
}
Sometimes you want to use the same pattern in Java, but you can't; at least not directly. Instead you could do something like this:
void getValues(int[] arg1, int[] arg2) {
arg1[0] = 1;
arg2[0] = 2;
}
void caller() {
int[] x = new int[1];
int[] y = new int[1];
getValues(x, y);
System.out.println("Result: " + x[0] + " " + y[0]);
}
As was explained in previous answers, in Java you're passing a pointer to the array as a value into getValues. That is enough, because the method then modifies the array element, and by convention you're expecting element 0 to contain the return value. Obviously you can do this in other ways, such as structuring your code so this isn't necessary, or constructing a class that can contain the return value or allow it to be set. But the simple pattern available to you in C++ above is not available in Java.
The distinction, or perhaps just the way I remember as I used to be under the same impression as the original poster is this: Java is always pass by value. All objects( in Java, anything except for primitives) in Java are references. These references are passed by value.
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;
}
}
Here is another example that will help you understand the difference (the classic swap example):
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;
}
}
Prints:
Before: a = 2, b = 3
After: a = 2, b = 3
This happens because iA and iB are new local reference variables that have the same value of the passed references (they point to a and b respectively). So, trying to change the references of iA or iB will only change in the local scope and not outside of this method.
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的输出:
名称= maxx
名称= fido
原始包装器类和字符串是不可变的,因此使用这些类型的任何示例都不会与其他类型/对象相同。
I always think of it as "pass by copy". It is a copy of the value be it primitive or reference. If it is a primitive it is a copy of the bits that are the value and if it is an Object it is a copy of the reference.
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;
}
}
output of java PassByCopy:
name= Maxx
name= Fido
Primitive wrapper classes and Strings are immutable so any example using those types will not work the same as other types/objects.
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();
}
Java has only pass by value. A very simple example to validate this.
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();
}
public class Test
{
public static int[] reverseArray(int[] array1)
{
int[] array2 = { -7, 0, -1 };
array1[0] = 5; // array a becomes 5, 10, -7
array1 = array2; /* array1 of reverseArray starts
pointing to c instead of a (not shown in image below) */
return array2;
}
public static void main(String[] args)
{
int[] array1 = { 1, 10, -7 };
int[] array2 = { 5, -190, 0 };
array1 = reverseArray(array1); /* array1 of
main starts pointing to c instead of a */
}
}
Unlike some other languages, Java does not allow you to choose between pass-by-value and pass-by-reference—all arguments are passed by value. A method call can pass two types of values to a method—copies of primitive values (e.g., values of int and double) and copies of references to objects.
When a method modifies a primitive-type parameter, changes to the parameter have no effect on the original argument value in the calling method.
When it comes to objects, objects themselves cannot be passed to methods. So we pass the reference(address) of the object. We can manipulate the original object using this reference.
How Java creates and stores objects: When we create an object we store the object’s address in a reference variable. Let's analyze the following statement.
Account account1 = new Account();
“Account account1” is the type and name of the reference variable, “=” is the assignment operator, “new” asks for the required amount of space from the system. The constructor to the right of keyword new which creates the object is called implicitly by the keyword new. Address of the created object(result of right value, which is an expression called "class instance creation expression") is assigned to the left value (which is a reference variable with a name and a type specified) using the assign operator.
Although an object’s reference is passed by value, a method can still interact with the referenced object by calling its public methods using the copy of the object’s reference. Since the reference stored in the parameter is a copy of the reference that was passed as an argument, the parameter in the called method and the argument in the calling method refer to the same object in memory.
Passing references to arrays, instead of the array objects themselves, makes sense for performance reasons. Because everything in Java is passed by value, if array objects were passed,
a copy of each element would be passed. For large arrays, this would waste time and consume
considerable storage for the copies of the elements.
In the image below you can see we have two reference variables(These are called pointers in C/C++, and I think that term makes it easier to understand this feature.) in the main method. Primitive and reference variables are kept in stack memory(left side in images below). array1 and array2 reference variables "point" (as C/C++ programmers call it) or reference to a and b arrays respectively, which are objects (values these reference variables hold are addresses of objects) in heap memory (right side in images below).
If we pass the value of array1 reference variable as an argument to the reverseArray method, a reference variable is created in the method and that reference variable starts pointing to the same array (a).
public class Test
{
public static void reverseArray(int[] array1)
{
// ...
}
public static void main(String[] args)
{
int[] array1 = { 1, 10, -7 };
int[] array2 = { 5, -190, 0 };
reverseArray(array1);
}
}
So, if we say
array1[0] = 5;
in reverseArray method, it will make a change in array a.
We have another reference variable in reverseArray method (array2) that points to an array c. If we were to say
array1 = array2;
in reverseArray method, then the reference variable array1 in method reverseArray would stop pointing to array a and start pointing to array c (Dotted line in second image).
If we return value of reference variable array2 as the return value of method reverseArray and assign this value to reference variable array1 in main method, array1 in main will start pointing to array c.
So let's write all the things we have done at once now.
public class Test
{
public static int[] reverseArray(int[] array1)
{
int[] array2 = { -7, 0, -1 };
array1[0] = 5; // array a becomes 5, 10, -7
array1 = array2; /* array1 of reverseArray starts
pointing to c instead of a (not shown in image below) */
return array2;
}
public static void main(String[] args)
{
int[] array1 = { 1, 10, -7 };
int[] array2 = { 5, -190, 0 };
array1 = reverseArray(array1); /* array1 of
main starts pointing to c instead of a */
}
}
And now that reverseArray method is over, its reference variables(array1 and array2) are gone. Which means we now only have the two reference variables in main method array1 and array2 which point to c and b arrays respectively. No reference variable is pointing to object (array) a. So it is eligible for garbage collection.
You could also assign value of array2 in main to array1. array1 would start pointing to b.
这听起来很奇怪而令人困惑吗?让我们考虑C通过参考来实施并按价值传递。在C中,默认约定按值通过。 void foo(int x)通过值传递。 void foo(int *x)是一个不需要 int a 的函数,而是指向int的指针: foo(&amp; a)代码>。一个人会将其与&amp; 运算符一起传递变量地址。
将其带到C ++,我们有参考。引用基本上是(在此上下文中)隐藏方程指针部分的句法糖: void foo(int&amp; x)由 foo(a)调用,其中,其中编译器本身知道它是参考,并且应传递非参考 a 的地址。在Java中,参考对象的所有变量实际上都是参考类型,实际上是通过参考来强制呼叫,以实现大多数意图和目的,而无需例如C ++提供的精细粒度控制(和复杂性)。
To make a long story short, Java objects have some very peculiar properties.
In general, Java has primitive types (int, bool, char, double, etc) that are passed directly by value. Then Java has objects (everything that derives from java.lang.Object). Objects are actually always handled through a reference (a reference being a pointer that you can't touch). That means that in effect, objects are passed by reference, as the references are normally not interesting. It does however mean that you cannot change which object is pointed to as the reference itself is passed by value.
Does this sound strange and confusing? Let's consider how C implements pass by reference and pass by value. In C, the default convention is pass by value. void foo(int x) passes an int by value. void foo(int *x) is a function that does not want an int a, but a pointer to an int: foo(&a). One would use this with the & operator to pass a variable address.
Take this to C++, and we have references. References are basically (in this context) syntactic sugar that hide the pointer part of the equation: void foo(int &x) is called by foo(a), where the compiler itself knows that it is a reference and the address of the non-reference a should be passed. In Java, all variables referring to objects are actually of reference type, in effect forcing call by reference for most intends and purposes without the fine grained control (and complexity) afforded by, for example, C++.
"by value" is the only way in java to pass a parameter to a method
using methods from the object given as parameter will alter the
object as the references point to
the original objects. (if that
method itself alters some values)
public static void main(String[] args) {
Dog aDog = new Dog("Max");
Dog oldDog = aDog;
// we pass the object to foo
foo(aDog);
// aDog variable is still pointing to the "Max" dog when foo(...) returns
aDog.getName().equals("Max"); // true
aDog.getName().equals("Fifi"); // false
aDog == oldDog; // true
}
public static void foo(Dog d) {
d.getName().equals("Max"); // true
// change d inside of foo() to point to a new Dog instance construct red with name member variable set to "Fifi"
d = new Dog("Fifi");
d.getName().equals("Fifi"); // true
}
在此示例中, adog.getName()仍然会返回“ max” 。 main 中的值在函数 foo 中未更改,通过创建新的 dog ,其中名称成员变量设置为“ fifi” 因为对象引用是按值传递的。如果对象引用是通过参考传递的,则 adog.getName() in main 将返回“ fifi” 在调用 foo 。
同样:
public static void main(String[] args) {
Dog aDog = new Dog("Max");
Dog oldDog = aDog;
foo(aDog);
// when foo(...) returns, the name of the dog has been changed to "Fifi"
aDog.getName().equals("Fifi"); // true
// but it is still the same dog:
aDog == oldDog; // true
}
public static void foo(Dog d) {
d.getName().equals("Max"); // true
// this changes the name of d to be "Fifi"
d.setName("Fifi");
}
The terms "pass-by-value" and "pass-by-reference" have special, precisely defined meanings in computer science. These meanings differ from the intuition many people have when first hearing the terms. Much of the confusion in this discussion seems to come from this fact.
The terms "pass-by-value" and "pass-by-reference" are talking about variables. Pass-by-value means that the value of a variable is passed to a function/method. Pass-by-reference means that a reference to that variable is passed to the function. The latter gives the function a way to change the contents of the variable.
By those definitions, Java is always pass-by-value. Unfortunately, when we deal with variables holding objects we are really dealing with object-handles called references which are passed-by-value as well. This terminology and semantics easily confuse many beginners.
It goes like this:
public static void main(String[] args) {
Dog aDog = new Dog("Max");
Dog oldDog = aDog;
// we pass the object to foo
foo(aDog);
// aDog variable is still pointing to the "Max" dog when foo(...) returns
aDog.getName().equals("Max"); // true
aDog.getName().equals("Fifi"); // false
aDog == oldDog; // true
}
public static void foo(Dog d) {
d.getName().equals("Max"); // true
// change d inside of foo() to point to a new Dog instance construct red with name member variable set to "Fifi"
d = new Dog("Fifi");
d.getName().equals("Fifi"); // true
}
In this example, aDog.getName() will still return "Max". The value aDog within main is not changed in the function foo by creating new Dog with name member variable set to "Fifi" because the object reference is passed by value. If the object reference was passed by reference, then the aDog.getName() in main would return "Fifi" after the call to foo.
Likewise:
public static void main(String[] args) {
Dog aDog = new Dog("Max");
Dog oldDog = aDog;
foo(aDog);
// when foo(...) returns, the name of the dog has been changed to "Fifi"
aDog.getName().equals("Fifi"); // true
// but it is still the same dog:
aDog == oldDog; // true
}
public static void foo(Dog d) {
d.getName().equals("Max"); // true
// this changes the name of d to be "Fifi"
d.setName("Fifi");
}
In this example, Fifi is dog’s name after call to foo(aDog) because the object's name was set inside of foo(...). Any operations that foo performs on d are such that, for all practical purposes, they are performed on aDog, but it is not possible to change the value of the variable aDog itself.
For more information on pass by reference and pass by value, consult the following answer: https://stackoverflow.com/a/430958/6005228. This explains more thoroughly the semantics and history behind the two and also explains why Java and many other modern languages appear to do both in certain cases.
The Java Spec says that everything in Java is pass-by-value. There is no such thing as "pass-by-reference" in Java.
The key to understanding this is that something like
Dog myDog;
is not a Dog; it's actually a pointer to a Dog. The use of the term "reference" in Java is very misleading and is what causes most of the confusion here. What they call "references" act/feel more like what we'd call "pointers" in most other languages.
What that means, is when you have
Dog myDog = new Dog("Rover");
foo(myDog);
you're essentially passing the address of the created Dog object to the foo method.
(I say essentially because Java pointers/references aren't direct addresses, but it's easiest to think of them that way.)
Suppose the Dog object resides at memory address 42. This means we pass 42 to the method.
if the Method were defined as
public void foo(Dog someDog) {
someDog.setName("Max"); // AAA
someDog = new Dog("Fifi"); // BBB
someDog.setName("Rowlf"); // CCC
}
let's look at what's happening.
the parameter someDog is set to the value 42
at line "AAA"
someDog is followed to the Dog it points to (the Dog object at address 42)
that Dog (the one at address 42) is asked to change his name to Max
at line "BBB"
a new Dog is created. Let's say he's at address 74
we assign the parameter someDog to 74
at line "CCC"
someDog is followed to the Dog it points to (the Dog object at address 74)
that Dog (the one at address 74) is asked to change his name to Rowlf
then, we return
Now let's think about what happens outside the method:
Did myDog change?
There's the key.
Keeping in mind that myDog is a pointer, and not an actual Dog, the answer is NO. myDog still has the value 42; it's still pointing to the original Dog (but note that because of line "AAA", its name is now "Max" - still the same Dog; myDog's value has not changed.)
It's perfectly valid to follow an address and change what's at the end of it; that does not change the variable, however.
Java works exactly like C. You can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, the caller will not see any changes you make to where that pointer points. (In a language with pass-by-reference semantics, the method function can change the pointer and the caller will see that change.)
In C++, Ada, Pascal and other languages that support pass-by-reference, you can actually change the variable that was passed.
If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB.
Think of reference parameters as being aliases for the variable passed in. When that alias is assigned, so is the variable that was passed in.
Update
A discussion in the comments warrants some clarification...
In C, you can write
void swap(int *x, int *y) {
int t = *x;
*x = *y;
*y = t;
}
int x = 1;
int y = 2;
swap(&x, &y);
This is not a special case in C. Both languages use pass-by-value semantics. Here the call site is creating additional data structure to assist the function to access and manipulate data.
The function is being passed pointers to data, and follows those pointers to access and modify that data.
A similar approach in Java, where the caller sets up assisting structure, might be:
void swap(int[] x, int[] y) {
int temp = x[0];
x[0] = y[0];
y[0] = temp;
}
int[] x = {1};
int[] y = {2};
swap(x, y);
(or if you wanted both examples to demonstrate features the other language doesn't have, create a mutable IntWrapper class to use in place of the arrays)
In these cases, both C and Java are simulating pass-by-reference. They're still both passing values (pointers to ints or arrays), and following those pointers inside the called function to manipulate the data.
Pass-by-reference is all about the function declaration/definition, and how it handles its parameters. Reference semantics apply to every call to that function, and the call site only needs to pass variables, no additional data structure.
These simulations require the call site and the function to cooperate. No doubt it's useful, but it's still pass-by-value.
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的参考 type foo 的 and type foo 带有属性“ f” 。。
foo f = new foo(“ f”);
来自方法侧,类型 foo 的引用名称 a 被声明,最初分配了 null 。
公共静态空隙转换(foo a)
当您调用方法 chanderference ,参考, 将分配作为参数传递的对象。
Changerference(F);
并为其分配一个类型 foo 的新对象“ b” 。
。
foo b = new foo(“ b”);
a = b 为参考 a ,不是 f ,其属性为“ b” 。
您调用 modifyReference(foo c) 方法 c 是创建并分配了具有属性的对象“ f” 。
c.setAttribute(“ c”); 将更改引用 c 指向的对象的属性,它是引用 f 指向它的对象。
Java always passes arguments by value, NOT by reference.
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");
}
}
I will explain this in steps:
Declaring a reference named f of type Foo and assign it a new object of type Foo with an attribute "f".
Foo f = new Foo("f");
From the method side, a reference of type Foo with a name a is declared and it's initially assigned null.
public static void changeReference(Foo a)
As you call the method changeReference, the reference a will be assigned the object which is passed as an argument.
changeReference(f);
Declaring a reference named b of type Foo and assign it a new object of type Foo with an attribute "b".
Foo b = new Foo("b");
a = b makes a new assignment to the reference a, notf, of the object whose attribute is "b".
As you call modifyReference(Foo c) method, a reference c is created and assigned the object with attribute "f".
c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's the same object that reference f points to it.
因此,如果您有 dosomething(foo)和 public void dosomething(foo foo){..} 这两个foos已复制了参考,则指向这一点。相同的对象。
自然,通过对象的价值传递给对象的引用看起来非常类似(实际上是无法区分的)通过引用传递对象。
Java is always pass by value, with no exceptions, ever.
So how is it that anyone can be at all confused by this, and believe that Java is pass by reference, or think they have an example of Java acting as pass by reference? The key point is that Java never provides direct access to the values of objects themselves, in any circumstances. The only access to objects is through a reference to that object. Because Java objects are always accessed through a reference, rather than directly, it is common to talk about fields and variables and method arguments as being objects, when pedantically they are only references to objects. The confusion stems from this (strictly speaking, incorrect) change in nomenclature.
So, when calling a method
For primitive arguments (int, long, etc.), the pass by value is the actual value of the primitive (for example, 3).
For objects, the pass by value is the value of the reference to the object.
So if you have doSomething(foo) and public void doSomething(Foo foo) { .. } the two Foos have copied references that point to the same objects.
Naturally, passing by value a reference to an object looks very much like (and is indistinguishable in practice from) passing an object by reference.
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 授予对人对象的引用。也就是说,它的地址。假设3bad086a。
This will give you some insights of how Java really works to the point that in your next discussion about Java passing by reference or passing by value you'll just smile :-)
Step one please erase from your mind that word that starts with 'p' "_ _ _ _ _ _ _", especially if you come from other programming languages. Java and 'p' cannot be written in the same book, forum, or even txt.
Step two remember that when you pass an Object into a method you're passing the Object reference and not the Object itself.
Student: Master, does this mean that Java is pass-by-reference?
Master: Grasshopper, No.
Now think of what an Object's reference/variable does/is:
A variable holds the bits that tell the JVM how to get to the referenced Object in memory (Heap).
When passing arguments to a method you ARE NOT passing the reference variable, but a copy of the bits in the reference variable. Something like this: 3bad086a. 3bad086a represents a way to get to the passed object.
So you're just passing 3bad086a that it's the value of the reference.
You're passing the value of the reference and not the reference itself (and not the object).
This value is actually COPIED and given to the method.
In the following (please don't try to compile/execute this...):
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. }
What happens?
The variable person is created in line #1 and it's null at the beginning.
A new Person Object is created in line #2, stored in memory, and the variable person is given the reference to the Person object. That is, its address. Let's say 3bad086a.
The variable person holding the address of the Object is passed to the function in line #3.
In line #4 you can listen to the sound of silence
Check the comment on line #5
A method local variable -anotherReferenceToTheSamePersonObject- is created and then comes the magic in line #6:
The variable/reference person is copied bit-by-bit and passed to anotherReferenceToTheSamePersonObject inside the function.
No new instances of Person are created.
Both "person" and "anotherReferenceToTheSamePersonObject" hold the same value of 3bad086a.
Don't try this but person==anotherReferenceToTheSamePersonObject would be true.
Both variables have IDENTICAL COPIES of the reference and they both refer to the same Person Object, the SAME Object on the Heap and NOT A COPY.
A picture is worth a thousand words:
Note that the anotherReferenceToTheSamePersonObject arrows is directed towards the Object and not towards the variable person!
If you didn't get it then just trust me and remember that it's better to say that Java is pass by value. Well, pass by reference value. Oh well, even better is pass-by-copy-of-the-variable-value! ;)
Now feel free to hate me but note that given this there is no difference between passing primitive data types and Objects when talking about method arguments.
You always pass a copy of the bits of the value of the reference!
If it's a primitive data type these bits will contain the value of the primitive data type itself.
If it's an Object the bits will contain the value of the address that tells the JVM how to get to the Object.
Java is pass-by-value because inside a method you can modify the referenced Object as much as you want but no matter how hard you try you'll never be able to modify the passed variable that will keep referencing (not p _ _ _ _ _ _ _) the same Object no matter what!
The changeName function above will never be able to modify the actual content (the bit values) of the passed reference. In other word changeName cannot make Person person refer to another Object.
Of course you can cut it short and just say that Java is pass-by-value!
private static void shout(String name){
System.out.println("There goes " + name + "!");
}
public static void main(String[] args){
String hisName = "John J. Jingleheimerschmitz";
String myName = hisName;
shout(myName);
}
创建一个字符串并在堆中分配空间,并且该字符串的地址存储在堆栈上,并给定标识符 hisname ,因为第二个字符串的地址与首先,没有创建新的字符串,也没有分配新的堆空间,但是在堆栈上创建了一个新的标识符。然后,我们调用 shout():创建了一个新的堆栈框架,并创建了一个新的标识符, name 将创建并分配了已经存在的字符串的地址。
”你说“土豆”。
I feel like arguing about pass-by-reference vs pass-by-value is not really helpful.
If you say that Java is pass-by-whatever, you are not providing a complete answer. Here is some additional information that will hopefully help you understand what actually happens in memory.
Crash course on stack/heap before we get to the Java implementation:
Values go on and off the stack in a nice orderly fashion, like a stack of plates at a cafeteria.
Memory in the heap (also known as dynamic memory) is haphazard and disorganized. The JVM just finds space wherever it can, and frees it up as the variables that use it are no longer needed.
Okay. First off, local primitives go on the stack. So this code:
int x = 3;
float y = 101.1f;
boolean amIAwesome = true;
results in this:
When you declare and instantiate an object. The actual object goes on the heap. What goes on the stack? The address of the object on the heap. C++ programmers would call this a pointer, but some Java developers are against the word "pointer". Whatever. Just know that the address of the object goes on the stack.
Like so:
int problems = 99;
String name = "Jay-Z";
An array is an object, so it goes on the heap as well. And what about the objects in the array? They get their own heap space, and the address of each object goes inside the array.
JButton[] marxBros = new JButton[3];
marxBros[0] = new JButton("Groucho");
marxBros[1] = new JButton("Zeppo");
marxBros[2] = new JButton("Harpo");
So, what gets passed in when you call a method? If you pass in an object, what you're actually passing in is the address of the object. Some might say the "value" of the address, and some say it's just a reference to the object. This is the genesis of the holy war between "reference" and "value" proponents. What you call it isn't as important as that you understand that what's getting passed in is the address to the object.
private static void shout(String name){
System.out.println("There goes " + name + "!");
}
public static void main(String[] args){
String hisName = "John J. Jingleheimerschmitz";
String myName = hisName;
shout(myName);
}
One String gets created and space for it is allocated in the heap, and the address to the string is stored on the stack and given the identifier hisName, since the address of the second String is the same as the first, no new String is created and no new heap space is allocated, but a new identifier is created on the stack. Then we call shout(): a new stack frame is created and a new identifier, name is created and assigned the address of the already-existing String.
will print out "Hah!" instead of null. The reason this works is because bar is a copy of the value of baz, which is just a reference to "Hah!". If it were the actual reference itself, then foo would have redefined baz to null.
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只有两种类型的传递:内置类型的值,以及对象类型的指针的值。
Just to show the contrast, compare the following C++ and Java snippets:
In C++: Note: Bad code - memory leaks! But it demonstrates the point.
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"
}
In 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 only has the two types of passing: by value for built-in types, and by value of the pointer for object types.
I can't believe that nobody mentioned Barbara Liskov yet. When she designed CLU in 1974, she ran into this same terminology problem, and she invented the term call by sharing (also known as call by object-sharing and call by object) for this specific case of "call by value where the value is a reference".
The crux of the matter is that the word reference in the expression "pass by reference" means something completely different from the usual meaning of the word reference in Java.
Usually in Java reference means a a reference to an object. But the technical terms pass by reference/value from programming language theory is talking about a reference to the memory cell holding the variable, which is something completely different.
using namespace std;
#include <iostream>
void change (char *&str){ // the '&' makes this a reference parameter
str = NULL;
}
int main()
{
char *str = "not Null";
change(str);
cout<<"str is " << str; // ==>str is <null>
}
Java通过“ java参考” value示例
public class ValueDemo{
public void change (String str){
str = null;
}
public static void main(String []args){
ValueDemo vd = new ValueDemo();
String str = "not null";
vd.change(str);
System.out.println("str is " + str); // ==> str is not null!!
// Note that if "str" was
// passed-by-reference, it
// WOULD BE NULL after the
// call to change().
}
}
program passByRefDemo;
type
iptr = ^integer;
var
ptr: iptr;
procedure setToNil(var ptr : iptr);
begin
ptr := nil;
end;
begin
new(ptr);
ptr^ := 10;
setToNil(ptr);
if (ptr = nil) then
writeln('ptr seems to be nil'); { ptr should be nil, so this line will run. }
end.
编辑2
的一些摘录“ Java编程语言” 撰写的 James Gosling(发明了Java)和David Holmes,以及David Holmes,第2章,第2.6.5节
There are already great answers that cover this. I wanted to make a small contribution by sharing a very simple example (which will compile) contrasting the behaviors between Pass-by-reference in c++ and Pass-by-value in Java.
A few points:
The term "reference" is a overloaded with two separate meanings. In Java it simply means a pointer, but in the context of "Pass-by-reference" it means a handle to the original variable which was passed in.
Java is Pass-by-value. Java is a descendent of C (among other languages). Before C, several (but not all) earlier languages like FORTRAN and COBOL supported PBR, but C did not. PBR allowed these other languages to make changes to the passed variables inside sub-routines. In order to accomplish the same thing (i.e. change the values of variables inside functions), C programmers passed pointers to variables into functions. Languages inspired by C, such as Java, borrowed this idea and continue to pass pointer to methods as C did, except that Java calls its pointers References. Again, this is a different use of the word "Reference" than in "Pass-By-Reference".
C++ allows Pass-by-reference by declaring a reference parameter using the "&" character (which happens to be the same character used to indicate "the address of a variable" in both C and C++). For example, if we pass in a pointer by reference, the parameter and the argument are not just pointing to the same object. Rather, they are the same variable. If one gets set to a different address or to null, so does the other.
In the C++ example below I'm passing a pointer to a null terminated string by reference. And in the Java example below I'm passing a Java reference to a String (again, the same as a pointer to a String) by value. Notice the output in the comments.
C++ pass by reference example:
using namespace std;
#include <iostream>
void change (char *&str){ // the '&' makes this a reference parameter
str = NULL;
}
int main()
{
char *str = "not Null";
change(str);
cout<<"str is " << str; // ==>str is <null>
}
Java pass "a Java reference" by value example
public class ValueDemo{
public void change (String str){
str = null;
}
public static void main(String []args){
ValueDemo vd = new ValueDemo();
String str = "not null";
vd.change(str);
System.out.println("str is " + str); // ==> str is not null!!
// Note that if "str" was
// passed-by-reference, it
// WOULD BE NULL after the
// call to change().
}
}
EDIT
Several people have written comments which seem to indicate that either they are not looking at my examples or they don't get the c++ example. Not sure where the disconnect is, but guessing the c++ example is not clear. I'm posting the same example in pascal because I think pass-by-reference looks cleaner in pascal, but I could be wrong. I might just be confusing people more; I hope not.
In pascal, parameters passed-by-reference are called "var parameters". In the procedure setToNil below, please note the keyword 'var' which precedes the parameter 'ptr'. When a pointer is passed to this procedure, it will be passed by reference. Note the behavior: when this procedure sets ptr to nil (that's pascal speak for NULL), it will set the argument to nil--you can't do that in Java.
program passByRefDemo;
type
iptr = ^integer;
var
ptr: iptr;
procedure setToNil(var ptr : iptr);
begin
ptr := nil;
end;
begin
new(ptr);
ptr^ := 10;
setToNil(ptr);
if (ptr = nil) then
writeln('ptr seems to be nil'); { ptr should be nil, so this line will run. }
end.
EDIT 2
Some excerpts from "THE Java Programming Language" by Ken Arnold, James Gosling (the guy who invented Java), and David Holmes, chapter 2, section 2.6.5
All parameters to methods are passed "by value". In other words,
values of parameter variables in a method are copies of the invoker
specified as arguments.
He goes on to make the same point regarding objects . . .
You should note that when the parameter is an object reference, it is
the object reference-not the object itself-that is passed "by value".
And towards the end of the same section he makes a broader statement about java being only pass by value and never pass by reference.
The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same
reference refer to the same actual object, changes made through one
reference variable are visible through the other. There is exactly one
parameter passing mode-pass by value-and that helps keep things
simple.
This section of the book has a great explanation of parameter passing in Java and of the distinction between pass-by-reference and pass-by-value and it's by the creator of Java. I would encourage anyone to read it, especially if you're still not convinced.
I think the difference between the two models is very subtle and unless you've done programming where you actually used pass-by-reference, it's easy to miss where two models differ.
I hope this settles the debate, but probably won't.
EDIT 3
I might be a little obsessed with this post. Probably because I feel that the makers of Java inadvertently spread misinformation. If instead of using the word "reference" for pointers they had used something else, say
dingleberry, there would've been no problem. You could say, "Java passes dingleberries by value and not by reference", and nobody would be confused.
That's the reason only Java developers have issue with this. They look at the word "reference" and think they know exactly what that means, so they don't even bother to consider the opposing argument.
Anyway, I noticed a comment in an older post, which made a balloon analogy which I really liked. So much so that I decided to glue together some clip-art to make a set of cartoons to illustrate the point.
Passing a reference by value--Changes to the reference are not reflected in the caller's scope, but the changes to the object are. This is because the reference is copied, but the both the original and the copy refer to the same object.
Pass by reference--There is no copy of the reference. Single reference is shared by both the caller and the function being called. Any changes to the reference or the Object's data are reflected in the caller's scope.
EDIT 4
I have seen posts on this topic which describe the low level implementation of parameter passing in Java, which I think is great and very helpful because it makes an abstract idea concrete. However, to me the question is more about the behavior described in the language specification than about the technical implementation of the behavior. This is an exerpt from the Java Language Specification, section 8.4.1 :
When the method or constructor is invoked (§15.12), the values of the
actual argument expressions initialize newly created parameter
variables, each of the declared type, before execution of the body of
the method or constructor. The Identifier that appears in the
DeclaratorId may be used as a simple name in the body of the method or
constructor to refer to the formal parameter.
Which means, java creates a copy of the passed parameters before executing a method. Like most people who studied compilers in college, I used "The Dragon Book" which is THE compilers book. It has a good description of "Call-by-value" and "Call-by-Reference" in Chapter 1. The Call-by-value description matches up with Java Specs exactly.
Back when I studied compilers-in the 90's, I used the first edition of the book from 1986 which pre-dated Java by about 9 or 10 years. However, I just ran across a copy of the 2nd Eddition from 2007 which actually mentions Java! Section 1.6.6 labeled "Parameter Passing Mechanisms" describes parameter passing pretty nicely. Here is an excerpt under the heading "Call-by-value" which mentions Java:
In call-by-value, the actual parameter is evaluated (if it is an
expression) or copied (if it is a variable). The value is placed in
the location belonging to the corresponding formal parameter of the
called procedure. This method is used in C and Java, and is a common
option in C++ , as well as in most other languages.
EDIT 5
Just asked copilot this questions:
There are some people on stackoverflow who assert that Java is a pass
by reference language. What's an insulting why to tell them they
are wrong.
The answer I got :
Ah, debating Java's pass-by-value nature can certainly stir up some
passionate responses! While it’s always best to keep discussions
constructive, if you’re looking for a clever way to correct
misconceptions, you could say something like:
"Java is as pass-by-reference as a hologram is a solid object. They're
confusing the copy of the reference with the reference itself. ????"
Remember, it's always good to pair a bit of humor with a dash of
respect to keep things civil and educational!
In java everything is reference, so when you have something like: Point pnt1 = new Point(0,0); Java does following:
Creates new Point object
Creates new Point reference and initialize that reference to point (refer to) on previously created Point object.
From here, through Point object life, you will access to that object through pnt1
reference. So we can say that in Java you manipulate object through its reference.
Java doesn't pass method arguments by reference; it passes them by value. I will use example from this site:
On this line 'pass-by-value' goes into the play...
tricky(pnt1,pnt2); public void tricky(Point arg1, Point arg2);
References pnt1 and pnt2 are passed by value to the tricky method, which means that now yours references pnt1 and pnt2 have their copies named arg1 and arg2.So pnt1 and arg1points to the same object. (Same for the pnt2 and arg2)
In the tricky method:
arg1.x = 100;
arg1.y = 100;
Next in the tricky method
Point temp = arg1;
arg1 = arg2;
arg2 = temp;
Here, you first create new temp Point reference which will point on same place like arg1 reference. Then you move reference arg1 to point to the same place like arg2 reference.
Finally arg2 will point to the same place like temp.
From here scope of tricky method is gone and you don't have access any more to the references: arg1, arg2, temp. But important note is that everything you do with these references when they are 'in life' will permanently affect object on which they are point to.
So after executing method tricky, when you return to main, you have this situation:
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;
}
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;
}
Java is always pass by value, not pass by reference
First of all, we need to understand what pass by value and pass by reference are.
Pass by value means that you are making a copy in memory of the actual parameter's value that is passed in. This is a copy of the contents of the actual parameter.
Pass by reference (also called pass by address) means that a copy of the address of the actual parameter is stored.
Sometimes Java can give the illusion of pass by reference. Let's see how it works by using the example below:
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;
}
The output of this program is:
changevalue
Let's understand step by step:
Test t = new Test();
As we all know it will create an object in the heap and return the reference value back to t. For example, suppose the value of t is 0x100234 (we don't know the actual JVM internal value, this is just an example) .
new PassByValue().changeValue(t);
When passing reference t to the function it will not directly pass the actual reference value of object test, but it will create a copy of t and then pass it to the function. Since it is passing by value, it passes a copy of the variable rather than the actual reference of it. Since we said the value of t was 0x100234, both t and f will have the same value and hence they will point to the same object.
If you change anything in the function using reference f it will modify the existing contents of the object. That is why we got the output changevalue, which is updated in the function.
To understand this more clearly, consider the following example:
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;
}
Will this throw a NullPointerException? No, because it only passes a copy of the reference.
In the case of passing by reference, it could have thrown a NullPointerException, as seen below:
Let's first understand that where java stores primitive data type and object data type.
Primitive data types itself and object references are stored in the stack.
Objects themselves are stored in the heap.
It means, Stack memory stores primitive data types and also the
addresses of objects.
And you always pass a copy of the bits of the value of the reference.
If it's a primitive data type then these copied bits contain the value of the primitive data type itself, That's why when we change the value of argument inside the method then it does not reflect the changes outside.
If it's an object data type like Foo foo=new Foo() then in this case copy of the address of the object passes like file shortcut , suppose we have a text file abc.txt at C:\desktop and suppose we make shortcut of the same file and put this inside C:\desktop\abc-shortcut so when you access the file from C:\desktop\abc.txt and write 'Stack Overflow' and close the file and again you open the file from shortcut then you write ' is the largest online community for programmers to learn' then total file change will be 'Stack Overflow is the largest online community for programmers to learn' which means it doesn't matter from where you open the file , each time we were accessing the same file , here we can assume Foo as a file and suppose foo stored at 123hd7h(original address like C:\desktop\abc.txt ) address and 234jdid(copied address like C:\desktop\abc-shortcut which actually contains the original address of the file inside) ..
So for better understanding make shortcut file and feel..
内存中的数据具有位置,在该位置有一个值(字节,单词,无论如何)。在组装中,我们有一个方便的解决方案,可以将名称位置(又称变量),但是当编译代码时,汇编器简单地替换 name 在指定的位置就像您的浏览器一样,用IP地址代替域名。
直到核心,在技术上不可能在不代表任何语言的情况下对任何语言的任何内容进行引用(当它立即成为值时)。
假设我们有一个可变的foo,其位置位于内存中的第47个字节,其 value 是5。我们有另一个变量 ref2foo 位于内存中的第223个字节,其值将为47。此Ref2Foo可能是技术变量,而不是由程序明确创建。如果您只看5和47没有任何其他信息,您将仅看到两个值。
如果您将它们用作参考,则可以到达 5 我们必须旅行:
(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223] -> 47
(Foo)[47] -> 5
这是跳伞表的工作方式。
如果我们想用Foo的值调用方法/函数/过程,则有几种可能的方法将变量传递给该方法,具体取决于 Language 及其几种方法调用模式:
5被复制到CPU寄存器之一(即eax)。
5被推到堆栈。
47被复制到CPU寄存器之一
47推到堆栈中。
223被复制到CPU登记册之一。
223被推到堆栈。
在上述值以上的每个情况下,已经创建了现有值的,现在它正在使用接收方法来处理它。当您在方法中写“ foo”时,它要么从eax中读取,要么自动或double删除,该过程取决于语言的工作原理和/或foo指示的类型。这是对开发人员隐藏的,直到她绕过退出过程。因此,当表示时,A 参考是A value ,因为参考是必须处理的值(在语言层面上)。
A reference is always a value when represented, no matter what language you use.
Getting an outside of the box view, let's look at Assembly or some low level memory management. At the CPU level a reference to anything immediately becomes a value if it gets written to memory or to one of the CPU registers. (That is why pointer is a good definition. It is a value, which has a purpose at the same time).
Data in memory has a Location and at that location there is a value (byte,word, whatever). In Assembly we have a convenient solution to give a Name to certain Location (aka variable), but when compiling the code, the assembler simply replaces Name with the designated location just like your browser replaces domain names with IP addresses.
Down to the core it is technically impossible to pass a reference to anything in any language without representing it (when it immediately becomes a value).
Lets say we have a variable Foo, its Location is at the 47th byte in memory and its Value is 5. We have another variable Ref2Foo which is at 223rd byte in memory, and its value will be 47. This Ref2Foo might be a technical variable, not explicitly created by the program. If you just look at 5 and 47 without any other information, you will see just two Values.
If you use them as references then to reach to 5 we have to travel:
(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223] -> 47
(Foo)[47] -> 5
This is how jump-tables work.
If we want to call a method/function/procedure with Foo's value, there are a few possible way to pass the variable to the method, depending on the language and its several method invocation modes:
5 gets copied to one of the CPU registers (ie. EAX).
5 gets PUSHd to the stack.
47 gets copied to one of the CPU registers
47 PUSHd to the stack.
223 gets copied to one of the CPU registers.
223 gets PUSHd to the stack.
In every cases above a value - a copy of an existing value - has been created, it is now upto the receiving method to handle it. When you write "Foo" inside the method, it is either read out from EAX, or automatically dereferenced, or double dereferenced, the process depends on how the language works and/or what the type of Foo dictates. This is hidden from the developer until she circumvents the dereferencing process. So a reference is a value when represented, because a reference is a value that has to be processed (at language level).
Now we have passed Foo to the method:
in case 1. and 2. if you change Foo (Foo = 9) it only affects local scope as you have a copy of the Value. From inside the method we cannot even determine where in memory the original Foo was located.
in case 3. and 4. if you use default language constructs and change Foo (Foo = 11), it could change Foo globally (depends on the language, ie. Java or like Pascal's procedure findMin(x, y, z: integer;var m: integer);). However if the language allows you to circumvent the dereference process, you can change 47, say to 49. At that point Foo seems to have been changed if you read it, because you have changed the local pointer to it. And if you were to modify this Foo inside the method (Foo = 12) you will probably FUBAR the execution of the program (aka. segfault) because you will write to a different memory than expected, you can even modify an area that is destined to hold executable program and writing to it will modify running code (Foo is now not at 47). BUT Foo's value of 47 did not change globally, only the one inside the method, because 47 was also a copy to the method.
in case 5. and 6. if you modify 223 inside the method it creates the same mayhem as in 3. or 4. (a pointer, pointing to a now bad value, that is again used as a pointer) but this is still a local problem, as 223 was copied. However if you are able to dereference Ref2Foo (that is 223), reach to and modify the pointed value 47, say, to 49, it will affect Foo globally, because in this case the methods got a copy of 223 but the referenced 47 exists only once, and changing that to 49 will lead every Ref2Foo double-dereferencing to a wrong value.
Nitpicking on insignificant details, even languages that do pass-by-reference will pass values to functions, but those functions know that they have to use it for dereferencing purposes. This pass-the-reference-as-value is just hidden from the programmer because it is practically useless and the terminology is only pass-by-reference.
Strict pass-by-value is also useless, it would mean that a 100 Mbyte array should have to be copied every time we call a method with the array as argument, therefore Java cannot be stricly pass-by-value. Every language would pass a reference to this huge array (as a value) and either employs copy-on-write mechanism if that array can be changed locally inside the method or allows the method (as Java does) to modify the array globally (from the caller's view) and a few languages allows to modify the Value of the reference itself.
So in short and in Java's own terminology, Java is pass-by-value where value can be: either a real value or a value that is a representation of a reference.
字符串对象,通过声明 final 的数组持有字符,无法修改。
只能使用“新”来代替对象的地址。
使用“新”来更新变量,由于最初按值传递并复制了该变量,因此不会从外部访问对象。
In Java, method arguments are all passed by value :
Java arguments are all passed by value (the value or reference is copied when used by the method) :
In the case of primitive types, Java behaviour is simple:
The value is copied in another instance of the primitive type.
In case of Objects, this is the same:
Object variables are references (mem buckets holding only Object’s address instead of a primitive value) that was created using the "new" keyword, and are copied like primitive types.
The behaviour can appear different from primitive types: Because the copied object-variable contains the same address (to the same Object).
Object's content/members might still be modified within a method and later access outside, giving the illusion that the (containing) Object itself was passed by reference.
"String" Objects appear to be a good counter-example to the urban legend saying that "Objects are passed by reference":
In effect, using a method, you will never be able, to update the value of a String passed as argument:
A String Object, holds characters by an array declared final that can't be modified.
Only the address of the Object might be replaced by another using "new".
Using "new" to update the variable, will not let the Object be accessed from outside, since the variable was initially passed by value and copied.
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);
}
但是,您可以为这样的字符串制作包装器,这将使它能够与字符串一起使用:
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);
}
As far as I know, Java only knows call by value. This means for primitive datatypes you will work with an copy and for objects you will work with an copy of the reference to the objects. However I think there are some pitfalls; for example, this will not work:
public static void swap(StringBuffer s1, StringBuffer s2) {
StringBuffer temp = s1;
s1 = s2;
s2 = temp;
}
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("Hello");
StringBuffer s2 = new StringBuffer("World");
swap(s1, s2);
System.out.println(s1);
System.out.println(s2);
}
This will populate Hello World and not World Hello because in the swap function you use copys which have no impact on the references in the main. But if your objects are not immutable you can change it for example:
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);
}
This will populate Hello World on the command line. If you change StringBuffer into String it will produce just Hello because String is immutable. For example:
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);
}
However you could make a wrapper for String like this which would make it able to use it with Strings:
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: i believe this is also the reason to use StringBuffer when it comes to "adding" two Strings because you can modifie the original object which u can't with immutable objects like String is.
发布评论
评论(30)
不,这不是参考。
Java根据Java语言规范按价值划分:
No, it's not pass by reference.
Java is pass by value according to the Java Language Specification:
让我尝试在四个例子的帮助下解释我的理解。 java是通过value传递的,并且不通过
java
中的值通过值
,所有参数均按值传递,即呼叫者不可见分配方法参数。
*/
示例1:
结果
示例2:
/**
*
*按价值通过
*
*/
结果
示例3:
/**
这种“通过价值通过”的感觉“通过参考”
有些人说原始类型和“字符串”是“按价值传递” 的感觉
对象是“通过参考传递”。
但是从这个示例中,我们可以理解它仅按值划分,
请记住,在这里我们将参考作为价值传递。
IE:参考是按值传递的。
这就是为什么能够改变的原因,并且在本地范围之后仍然存在。
但是我们无法更改原始范围之外的实际参考。
passbyvalueobjectcase2的下一个示例证明了这意味着什么。
*/
结果
示例4:
/**
除了示例3(passbyvalueobjectcase1.java)中所述的内容外,我们无法更改原始范围之外的实际参考
。 的代码
私人班级
:我不粘贴
Let me try to explain my understanding with the help of four examples. Java is pass-by-value, and not pass-by-reference
/**
Pass By Value
In Java, all parameters are passed by value, i.e. assigning a method argument is not visible to the caller.
*/
Example 1:
Result
Example 2:
/**
*
* Pass By Value
*
*/
Result
Example 3:
/**
This 'Pass By Value has a feeling of 'Pass By Reference'
Some people say primitive types and 'String' are 'pass by value'
and objects are 'pass by reference'.
But from this example, we can understand that it is infact pass by value only,
keeping in mind that here we are passing the reference as the value.
ie: reference is passed by value.
That's why are able to change and still it holds true after the local scope.
But we cannot change the actual reference outside the original scope.
what that means is demonstrated by next example of PassByValueObjectCase2.
*/
Result
Example 4:
/**
In addition to what was mentioned in Example3 (PassByValueObjectCase1.java), we cannot change the actual reference outside the original scope."
Note: I am not pasting the code for
private class Student
. The class definition forStudent
is same as Example3.*/
Result
我认为我会为此做出贡献,以添加规格中的更多细节。
首先,通过参考VS通过参考VS的传递有什么区别通过价值通过?
或来自wikipedia, by-by-reference
and tops-by-value
其次,我们需要知道Java在其方法调用中使用了什么。 >状态
因此,它将参数值(或绑定)分配给相应的参数变量。
该参数的价值是什么?
让我们考虑参考类型, java虚拟机规范状态
Java语言规范也指出
参数(某些参考类型)的值是指向对象的指针。请注意,变量,具有参考类型返回类型的方法的调用以及实例创建表达式(
new ...
)都解散为参考类型值。因此,
全部将引用对
String
实例的值绑定到该方法新创建的参数,param
。这正是通过逐个价值所描述的定义。因此, java是逐个传递。您可以遵循参考来调用方法或访问引用对象的字段的事实与对话完全无关。通过参考的定义是
在Java中,修改变量意味着重新分配它。在Java中,如果您在方法中重新分配了变量,则不会对呼叫者忽略。 修改由变量引用的对象完全是一个不同的概念。
原始值在Java虚拟机规范中也定义了,在这里。该类型的值是适当编码的相应积分或浮点值(8、16、32、64等)。
I thought I'd contribute this answer to add more details from the Specifications.
First, What's the difference between passing by reference vs. passing by value?
Or from wikipedia, on the subject of pass-by-reference
And on the subject of pass-by-value
Second, we need to know what Java uses in its method invocations. The Java Language Specification states
So it assigns (or binds) the value of the argument to the corresponding parameter variable.
What is the value of the argument?
Let's consider reference types, the Java Virtual Machine Specification states
The Java Language Specification also states
The value of an argument (of some reference type) is a pointer to an object. Note that a variable, an invocation of a method with a reference type return type, and an instance creation expression (
new ...
) all resolve to a reference type value.So
all bind the value of a reference to a
String
instance to the method's newly created parameter,param
. This is exactly what the definition of pass-by-value describes. As such, Java is pass-by-value.The fact that you can follow the reference to invoke a method or access a field of the referenced object is completely irrelevant to the conversation. The definition of pass-by-reference was
In Java, modifying the variable means reassigning it. In Java, if you reassigned the variable within the method, it would go unnoticed to the caller. Modifying the object referenced by the variable is a different concept entirely.
Primitive values are also defined in the Java Virtual Machine Specification, here. The value of the type is the corresponding integral or floating point value, encoded appropriately (8, 16, 32, 64, etc. bits).
您永远无法通过Java中的参考来传递,并且很明显的方式之一是您想从方法调用中返回多个值时。考虑C ++中的以下代码:
有时您想在Java中使用相同的模式,但不能;至少不是直接。取而代之的是,您可以做这样的事情:
如先前答案中所述,在Java中,您将数组作为值的指针传递到
getValues
中。就足够了,因为该方法随后会修改数组元素,并且按照惯例,您期望元素0包含返回值。显然,您可以以其他方式进行此操作,例如构造代码,因此这不是必要的,也可以构建可以包含返回值或允许将其设置的类。但是,Java在上面的C ++中可用的简单模式在Java中不可用。You can never pass by reference in Java, and one of the ways that is obvious is when you want to return more than one value from a method call. Consider the following bit of code in C++:
Sometimes you want to use the same pattern in Java, but you can't; at least not directly. Instead you could do something like this:
As was explained in previous answers, in Java you're passing a pointer to the array as a value into
getValues
. That is enough, because the method then modifies the array element, and by convention you're expecting element 0 to contain the return value. Obviously you can do this in other ways, such as structuring your code so this isn't necessary, or constructing a class that can contain the return value or allow it to be set. But the simple pattern available to you in C++ above is not available in Java.与原始海报相同的印象是:java总是按价值传递。 Java中的所有对象(在Java中,除原始内容外)都是参考。这些参考文献是按值传递的。
The distinction, or perhaps just the way I remember as I used to be under the same impression as the original poster is this: Java is always pass by value. All objects( in Java, anything except for primitives) in Java are references. These references are passed by value.
正如许多人之前提到的那样,
这是另一个示例,可以帮助您了解差异(经典交换示例):
打印:
发生这种情况,因为IA和IB是具有相同值的新的局部参考变量(分别指向A和B)。因此,尝试更改IA或IB的参考文献只会在本地范围中而不在此方法之外。
As many people mentioned it before, Java is always pass-by-value
Here is another example that will help you understand the difference (the classic swap example):
Prints:
This happens because iA and iB are new local reference variables that have the same value of the passed references (they point to a and b respectively). So, trying to change the references of iA or iB will only change in the local scope and not outside of this method.
我一直认为它是“通过复制”。它是原始或参考的值的副本。如果是原始的,则是值的副本,如果它是对象,则是参考的副本。
Java PassbyCopy的输出:
原始包装器类和字符串是不可变的,因此使用这些类型的任何示例都不会与其他类型/对象相同。
I always think of it as "pass by copy". It is a copy of the value be it primitive or reference. If it is a primitive it is a copy of the bits that are the value and if it is an Object it is a copy of the reference.
output of java PassByCopy:
Primitive wrapper classes and Strings are immutable so any example using those types will not work the same as other types/objects.
Java仅按价值通过。一个非常简单的示例来验证这一点。
Java has only pass by value. A very simple example to validate this.
与其他某些语言不同,Java不允许您在通过逐票和通过参考的传递之间进行选择 - 所有参数都是按价值传递的。方法调用可以将两种类型的值传递给一种方法 - 原始值的论述(例如,int和double的值)以及对对象的引用的副本。
当方法修改原始型参数时,对参数的更改对调用方法中的原始参数值没有影响。
当涉及对象时,对象本身不能传递给方法。因此,我们传递对象的参考(地址)。我们可以使用此引用来操纵原始对象。
Java如何创建和存储对象:创建一个对象时,我们将对象的地址存储在参考变量中。让我们分析以下陈述。
“帐户1”是参考变量的类型和名称,“ =”是分配操作员,“新”要求从系统中提供所需的空间。创建对象的关键字新的右键的构造函数由关键字New隐式称为。创建对象的地址(正确值的结果,是一种称为“类实例创建表达式”的表达式),将使用分配操作员分配给左值(这是带有名称和类型的参考变量)。
尽管对象的引用是按值传递的,但通过使用对象的副本调用其公共方法,方法仍然可以与引用对象进行交互。由于参数中存储的参考是作为参数传递的参考文献的副本,因此在调用方法中的参数以及调用方法中的参数在内存中引用相同对象。
出于性能原因,传递对数组的引用,而不是数组对象本身是有意义的。因为Java中的所有内容都是按值传递的,如果通过数组对象,
每个元素的副本将通过。对于大型阵列,这会浪费时间并消耗
元素副本的大量存储空间。
在下面的图像中,您可以看到我们有两个参考变量(这些变量称为C/C ++,我认为该术语使理解此功能更容易理解。)在主方法中。原始变量和参考变量保存在堆栈内存中(下图中的左侧)。 array1和array2参考变量“点”(如c/c ++程序员称为)或分别对a和b数组的引用,它们是堆内存中的对象(值这些参考变量是对象的地址)(下图中的右侧) 。
如果我们将array1参考变量的值作为参数传递给reversearray方法,则在方法中创建一个参考变量,并且该参考变量开始指向同一数组(a)。
因此,如果我们在reververearray方法中说
,它将在数组中进行更改。
我们在反reverearray方法(array2)中有另一个引用变量,该变量指向数组c。如果我们要
在reververearray方法中说,那么ReverSearray中的参考变量array1将停止指向数组A并开始指向数组C(第二张图像中的虚线)。
如果我们返回参考变量array2作为方法reverseArray的返回值,并将此值分配给主方法中的参考变量array1,则main中的array1将开始指向数组c。
因此,让我们立即写下我们现在做的所有事情。
现在,反reversearray方法已经结束,其参考变量(array1和array2)已经消失。这意味着我们现在仅在主方法array1和array2中只有两个参考变量,分别指向C和B数组。没有参考变量指向对象(数组)a。因此,它有资格获得垃圾收集。
您也可以将array2的值分配给array1中。 array1将开始指向b。
Unlike some other languages, Java does not allow you to choose between pass-by-value and pass-by-reference—all arguments are passed by value. A method call can pass two types of values to a method—copies of primitive values (e.g., values of int and double) and copies of references to objects.
When a method modifies a primitive-type parameter, changes to the parameter have no effect on the original argument value in the calling method.
When it comes to objects, objects themselves cannot be passed to methods. So we pass the reference(address) of the object. We can manipulate the original object using this reference.
How Java creates and stores objects: When we create an object we store the object’s address in a reference variable. Let's analyze the following statement.
“Account account1” is the type and name of the reference variable, “=” is the assignment operator, “new” asks for the required amount of space from the system. The constructor to the right of keyword new which creates the object is called implicitly by the keyword new. Address of the created object(result of right value, which is an expression called "class instance creation expression") is assigned to the left value (which is a reference variable with a name and a type specified) using the assign operator.
Although an object’s reference is passed by value, a method can still interact with the referenced object by calling its public methods using the copy of the object’s reference. Since the reference stored in the parameter is a copy of the reference that was passed as an argument, the parameter in the called method and the argument in the calling method refer to the same object in memory.
Passing references to arrays, instead of the array objects themselves, makes sense for performance reasons. Because everything in Java is passed by value, if array objects were passed,
a copy of each element would be passed. For large arrays, this would waste time and consume
considerable storage for the copies of the elements.
In the image below you can see we have two reference variables(These are called pointers in C/C++, and I think that term makes it easier to understand this feature.) in the main method. Primitive and reference variables are kept in stack memory(left side in images below). array1 and array2 reference variables "point" (as C/C++ programmers call it) or reference to a and b arrays respectively, which are objects (values these reference variables hold are addresses of objects) in heap memory (right side in images below).
If we pass the value of array1 reference variable as an argument to the reverseArray method, a reference variable is created in the method and that reference variable starts pointing to the same array (a).
So, if we say
in reverseArray method, it will make a change in array a.
We have another reference variable in reverseArray method (array2) that points to an array c. If we were to say
in reverseArray method, then the reference variable array1 in method reverseArray would stop pointing to array a and start pointing to array c (Dotted line in second image).
If we return value of reference variable array2 as the return value of method reverseArray and assign this value to reference variable array1 in main method, array1 in main will start pointing to array c.
So let's write all the things we have done at once now.
And now that reverseArray method is over, its reference variables(array1 and array2) are gone. Which means we now only have the two reference variables in main method array1 and array2 which point to c and b arrays respectively. No reference variable is pointing to object (array) a. So it is eligible for garbage collection.
You could also assign value of array2 in main to array1. array1 would start pointing to b.
简而言之, java> java 对象具有一些非常特殊的属性。
通常,Java具有原始类型(
int
,bool
,char> char
,double
等)按价值。然后Java具有对象(从java.lang.object
衍生的所有内容)。实际上,对象总是通过参考来处理(参考是您无法触摸的指针)。这意味着实际上是通过引用传递对象的,因为参考通常不有趣。但是,这确实意味着您无法更改作为参考本身的对象的指向。这听起来很奇怪而令人困惑吗?让我们考虑C通过参考来实施并按价值传递。在C中,默认约定按值通过。
void foo(int x)
通过值传递。void foo(int *x)
是一个不需要int a
的函数,而是指向int的指针:foo(&amp; a)代码>。一个人会将其与
&amp;
运算符一起传递变量地址。将其带到C ++,我们有参考。引用基本上是(在此上下文中)隐藏方程指针部分的句法糖:
void foo(int&amp; x)
由foo(a)调用,其中
,其中编译器本身知道它是参考,并且应传递非参考a
的地址。在Java中,参考对象的所有变量实际上都是参考类型,实际上是通过参考来强制呼叫,以实现大多数意图和目的,而无需例如C ++提供的精细粒度控制(和复杂性)。To make a long story short, Java objects have some very peculiar properties.
In general, Java has primitive types (
int
,bool
,char
,double
, etc) that are passed directly by value. Then Java has objects (everything that derives fromjava.lang.Object
). Objects are actually always handled through a reference (a reference being a pointer that you can't touch). That means that in effect, objects are passed by reference, as the references are normally not interesting. It does however mean that you cannot change which object is pointed to as the reference itself is passed by value.Does this sound strange and confusing? Let's consider how C implements pass by reference and pass by value. In C, the default convention is pass by value.
void foo(int x)
passes an int by value.void foo(int *x)
is a function that does not want anint a
, but a pointer to an int:foo(&a)
. One would use this with the&
operator to pass a variable address.Take this to C++, and we have references. References are basically (in this context) syntactic sugar that hide the pointer part of the equation:
void foo(int &x)
is called byfoo(a)
, where the compiler itself knows that it is a reference and the address of the non-referencea
should be passed. In Java, all variables referring to objects are actually of reference type, in effect forcing call by reference for most intends and purposes without the fine grained control (and complexity) afforded by, for example, C++.我已经创建了一个专门针对任何 编程语言的线程-Value“>在这里。
Java也提到了。这是简短的摘要:
参考指向的对象
原始对象。 (如果那样
方法本身改变了一些值)
I have created a thread devoted to these kind of questions for any programming languages here.
Java is also mentioned. Here is the short summary:
object as the references point to
the original objects. (if that
method itself alters some values)
术语“通过价值”和“通过逐次参考”具有特殊性,精确定义了计算机科学中的含义。这些含义与许多人初次听到术语时的直觉不同。这次讨论中的许多混乱似乎来自这个事实。
术语“通过价值”和“通过引用”正在谈论变量。 by-by-value表示变量的 value 传递到函数/方法。通过引用意味着该变量的参考传递给该函数。后者为函数提供了更改变量内容的方法。
根据这些定义,Java始终是逐个值。不幸的是,当我们处理持有对象的变量时,我们确实正在处理称为参考的对象处理,这些对象也通过价值传递。这种术语和语义很容易使许多初学者感到困惑。
它是这样的:
在此示例中,
main 中的值在函数 foo 中未更改,通过创建新的
adog.getName()
仍然会返回“ max”
。dog
,其中名称成员变量设置为“ fifi”
因为对象引用是按值传递的。如果对象引用是通过参考传递的,则adog.getName()
inmain
将返回“ fifi”
在调用foo 。
同样:
在此示例中,
fifi
是狗的名称,请致电foo(adog)
,因为对象的名称是在foo(...)。
foo
在d
上执行的任何操作都使得它们在所有实际目的上都在adog
可以更改变量adog
本身的值。有关通过参考的通行信息的更多信息并按价值通过,请咨询以下答案: https://stackoverflow.com/a/430958/6005228/6005228/ 。这更彻底地解释了两者背后的语义和历史,也解释了为什么Java和许多其他现代语言在某些情况下似乎同时使用这两种语言。
The terms "pass-by-value" and "pass-by-reference" have special, precisely defined meanings in computer science. These meanings differ from the intuition many people have when first hearing the terms. Much of the confusion in this discussion seems to come from this fact.
The terms "pass-by-value" and "pass-by-reference" are talking about variables. Pass-by-value means that the value of a variable is passed to a function/method. Pass-by-reference means that a reference to that variable is passed to the function. The latter gives the function a way to change the contents of the variable.
By those definitions, Java is always pass-by-value. Unfortunately, when we deal with variables holding objects we are really dealing with object-handles called references which are passed-by-value as well. This terminology and semantics easily confuse many beginners.
It goes like this:
In this example,
aDog.getName()
will still return"Max"
. The valueaDog
withinmain
is not changed in the functionfoo
by creating newDog
with name member variable set to"Fifi"
because the object reference is passed by value. If the object reference was passed by reference, then theaDog.getName()
inmain
would return"Fifi"
after the call tofoo
.Likewise:
In this example,
Fifi
is dog’s name after call tofoo(aDog)
because the object's name was set inside offoo(...)
. Any operations thatfoo
performs ond
are such that, for all practical purposes, they are performed onaDog
, but it is not possible to change the value of the variableaDog
itself.For more information on pass by reference and pass by value, consult the following answer: https://stackoverflow.com/a/430958/6005228. This explains more thoroughly the semantics and history behind the two and also explains why Java and many other modern languages appear to do both in certain cases.
我刚刚注意到您引用了我的文章。
Java规格说,Java中的所有内容都是逐个通行的。 Java中没有“通过逐次参考”这样的东西。
理解这一点的关键是类似
不是的狗。实际上是狗的指针。 Java中“参考”一词的使用非常具有误导性,这是在这里引起大多数混乱的原因。他们所说的“参考”行为/感觉更像我们所说的大多数其他语言中的“指针”。
这意味着,当您拥有
创建
dog
对象的地址foo
方法时。(我说本质上是因为Java指针/参考不是直接地址,但最容易想到它们。)
假设
dog
对象位于内存地址42。这意味着我们将42传递给方法。如果将方法定义为
让我们看正在发生的事情。
某种程序
设置为有些
遵循dog
指向(dog
地址上的对象42)dog
(地址42上的一个)被要求将其名称更改为Max狗
。假设他在地址74某种程序
为74dog
的某种程序指向(dog
地址74的对象)Dog
(地址74上的一个)被要求将其名称更改为Rowlf现在返回,让我们考虑一下方法之外发生的事情:
di di di div 更改?
有密钥。
请记住,
myDog
是A Pointer ,而不是实际的dog
,答案是否。myDog
仍然具有值42;它仍然指向原始dog
(但请注意,由于“ AAA”行,其名称现在为“ max” - 仍然是同一狗;mydog
的值没有更改。)遵循一个地址并更改其末尾的内容是完全有效的;但是,这不会改变变量。
Java工作完全像C。您可以分配指针,将指针传递给方法,按照方法中的指针进行操作,然后更改指向的数据。但是,呼叫者不会看到您对指针指向的任何更改。 (用具有传递语义语义的语言,方法函数 can 更改指针,呼叫者将看到这种变化。)
在C ++,ADA,Pascal和其他支持通过 - 的语言中参考,您实际上可以更改通过的变量。
如果Java具有通过传递语义的传递语义,那么我们上面定义的
foo
方法将在myDog
指向poce> poce> posef
时将更改BBB。认为参考参数是传递变量的别名。当该别名分配时,传递的变量也是如此。
更新
在评论中
讨论值为某些澄清...在C中,您可以写作,
这不是一个C的特殊情况。两种语言都使用通过传递语义语义。在这里,呼叫站点正在创建其他数据结构,以帮助该功能访问和操纵数据。
该功能正在传递给数据,并遵循这些指针访问和修改数据。
,呼叫者设置辅助结构的类似方法可能是
:
在Java中 案例,C和Java均为模拟通过参考。它们仍然都传递值(指针到INT或数组),并遵循所谓函数中的指针来操纵数据。
通过引用是关于函数声明/定义的全部内容,以及它如何处理其参数。参考语义适用于每个呼叫该功能,呼叫站点只需要传递变量,而无需其他数据结构。
这些模拟需要呼叫站点和功能进行配合。毫无疑问,这很有用,但仍然可以通过。
I just noticed you referenced my article.
The Java Spec says that everything in Java is pass-by-value. There is no such thing as "pass-by-reference" in Java.
The key to understanding this is that something like
is not a Dog; it's actually a pointer to a Dog. The use of the term "reference" in Java is very misleading and is what causes most of the confusion here. What they call "references" act/feel more like what we'd call "pointers" in most other languages.
What that means, is when you have
you're essentially passing the address of the created
Dog
object to thefoo
method.(I say essentially because Java pointers/references aren't direct addresses, but it's easiest to think of them that way.)
Suppose the
Dog
object resides at memory address 42. This means we pass 42 to the method.if the Method were defined as
let's look at what's happening.
someDog
is set to the value 42someDog
is followed to theDog
it points to (theDog
object at address 42)Dog
(the one at address 42) is asked to change his name to MaxDog
is created. Let's say he's at address 74someDog
to 74Dog
it points to (theDog
object at address 74)Dog
(the one at address 74) is asked to change his name to RowlfNow let's think about what happens outside the method:
Did
myDog
change?There's the key.
Keeping in mind that
myDog
is a pointer, and not an actualDog
, the answer is NO.myDog
still has the value 42; it's still pointing to the originalDog
(but note that because of line "AAA", its name is now "Max" - still the same Dog;myDog
's value has not changed.)It's perfectly valid to follow an address and change what's at the end of it; that does not change the variable, however.
Java works exactly like C. You can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, the caller will not see any changes you make to where that pointer points. (In a language with pass-by-reference semantics, the method function can change the pointer and the caller will see that change.)
In C++, Ada, Pascal and other languages that support pass-by-reference, you can actually change the variable that was passed.
If Java had pass-by-reference semantics, the
foo
method we defined above would have changed wheremyDog
was pointing when it assignedsomeDog
on line BBB.Think of reference parameters as being aliases for the variable passed in. When that alias is assigned, so is the variable that was passed in.
Update
A discussion in the comments warrants some clarification...
In C, you can write
This is not a special case in C. Both languages use pass-by-value semantics. Here the call site is creating additional data structure to assist the function to access and manipulate data.
The function is being passed pointers to data, and follows those pointers to access and modify that data.
A similar approach in Java, where the caller sets up assisting structure, might be:
(or if you wanted both examples to demonstrate features the other language doesn't have, create a mutable IntWrapper class to use in place of the arrays)
In these cases, both C and Java are simulating pass-by-reference. They're still both passing values (pointers to ints or arrays), and following those pointers inside the called function to manipulate the data.
Pass-by-reference is all about the function declaration/definition, and how it handles its parameters. Reference semantics apply to every call to that function, and the call site only needs to pass variables, no additional data structure.
These simulations require the call site and the function to cooperate. No doubt it's useful, but it's still pass-by-value.
Java总是通过Value 传递参数,而不是通过参考。
让我通过示例:
我将在步骤中解释这一点:
声明名为
f的参考
typefoo
的 and typefoo
带有属性“ f”
。。来自方法侧,类型
foo
的引用名称a
被声明,最初分配了null
。当您调用方法
chanderference
,参考,
将分配作为参数传递的对象。foo
的新对象“ b” 。。
a = b
为参考a ,不是
f
,其属性为“ b”
。您调用
modifyReference(foo c)
方法c
是创建并分配了具有属性的对象“ f”
。c.setAttribute(“ c”);
将更改引用c
指向的对象的属性,它是引用f
指向它的对象。Java always passes arguments by value, NOT by reference.
Let me explain this through an example:
I will explain this in steps:
Declaring a reference named
f
of typeFoo
and assign it a new object of typeFoo
with an attribute"f"
.From the method side, a reference of type
Foo
with a namea
is declared and it's initially assignednull
.As you call the method
changeReference
, the referencea
will be assigned the object which is passed as an argument.Declaring a reference named
b
of typeFoo
and assign it a new object of typeFoo
with an attribute"b"
.a = b
makes a new assignment to the referencea
, notf
, of the object whose attribute is"b"
.As you call
modifyReference(Foo c)
method, a referencec
is created and assigned the object with attribute"f"
.c.setAttribute("c");
will change the attribute of the object that referencec
points to it, and it's the same object that referencef
points to it.Java总是按价值划分的,除了任何例外, ever 。
那么,任何人如何对此感到困惑,并相信Java是通过参考来传递的,或者认为他们有一个Java的例子,可以用参考作为通过?关键是Java 从不在任何 情况下直接访问对象本身的值。对对象的唯一访问是通过A 参考对该对象。因为Java对象是始终通过引用而不是直接访问的,所以谈论字段和变量和方法参数是 objects objects ,当他们进行良好的时,它们仅是对对象的引用。 混乱源于(严格地说,不正确)命名法的变化。
方法时
因此,如果您有
dosomething(foo)
和public void dosomething(foo foo){..}
这两个foos已复制了参考,则指向这一点。相同的对象。自然,通过对象的价值传递给对象的引用看起来非常类似(实际上是无法区分的)通过引用传递对象。
Java is always pass by value, with no exceptions, ever.
So how is it that anyone can be at all confused by this, and believe that Java is pass by reference, or think they have an example of Java acting as pass by reference? The key point is that Java never provides direct access to the values of objects themselves, in any circumstances. The only access to objects is through a reference to that object. Because Java objects are always accessed through a reference, rather than directly, it is common to talk about fields and variables and method arguments as being objects, when pedantically they are only references to objects. The confusion stems from this (strictly speaking, incorrect) change in nomenclature.
So, when calling a method
int
,long
, etc.), the pass by value is the actual value of the primitive (for example, 3).So if you have
doSomething(foo)
andpublic void doSomething(Foo foo) { .. }
the two Foos have copied references that point to the same objects.Naturally, passing by value a reference to an object looks very much like (and is indistinguishable in practice from) passing an object by reference.
这将为您提供一些有关Java如何真正起作用的见解,以至于您下一次讨论Java通过参考或通过价值传递的讨论,您只会微笑: - )
第一步请从您的脑海中删除那个以'p'开头的单词“ _ _ _ _ _ _ _ _”,特别是如果您来自其他编程语言。 Java和“ P”不能写在同一本书,论坛甚至TXT中。
第二步请记住,当您将对象传递到方法中时,您是传递对象引用的,而不是对象本身。
。
在下面(请不要尝试编译/执行此问题...):
会发生什么?
一张图片值得一千个字:
请注意,另一个referferenceTothEsamePersonObject arrows是针对对象的,而不是对象迈向变量人!
如果您不明白它,请相信我,并记住,最好说 java是按价值传递的。好吧,通过参考值通过。哦,好吧,更好的是 逐个副本可变值! ;)
现在可以随意恨我,但请注意,在谈论方法参数时,通过传递原始数据类型和对象之间没有区别。
您始终将参考价值的位副本传递!
当然,您可以将其简要剪切,然后说 java是按价值传递的!
This will give you some insights of how Java really works to the point that in your next discussion about Java passing by reference or passing by value you'll just smile :-)
Step one please erase from your mind that word that starts with 'p' "_ _ _ _ _ _ _", especially if you come from other programming languages. Java and 'p' cannot be written in the same book, forum, or even txt.
Step two remember that when you pass an Object into a method you're passing the Object reference and not the Object itself.
Now think of what an Object's reference/variable does/is:
In the following (please don't try to compile/execute this...):
What happens?
A picture is worth a thousand words:
Note that the anotherReferenceToTheSamePersonObject arrows is directed towards the Object and not towards the variable person!
If you didn't get it then just trust me and remember that it's better to say that Java is pass by value. Well, pass by reference value. Oh well, even better is pass-by-copy-of-the-variable-value! ;)
Now feel free to hate me but note that given this there is no difference between passing primitive data types and Objects when talking about method arguments.
You always pass a copy of the bits of the value of the reference!
Of course you can cut it short and just say that Java is pass-by-value!
Java按价值传递参考。
因此,您无法更改传递的参考。
Java passes references by value.
So you can't change the reference that gets passed in.
我觉得要争论通过参考 vs 通过by-value 并没有真正的帮助。
如果您说Java是逐个通行,您将无法提供完整的答案。这是一些其他信息,希望可以帮助您了解内存中实际发生的事情。
在进入Java实施之前,请堆栈/堆上的速成课程:
价值观以一种很好的有序方式在堆栈上进行,就像自助餐厅的一堆盘子一样。
堆中的内存(也称为动态内存)是随意的,混乱了。 JVM只能在任何地方找到空间,并将其释放为不再需要使用它的变量。
好的。首先,本地原始人堆在堆上。因此,此代码:
导致这样做:
“
声明和实例化对象”时。实际对象在堆上。堆栈上有什么?对象在堆上的地址。 C ++程序员将其称为指针,但是一些Java开发人员反对“指针”一词。任何。只知道对象的地址在堆栈上。
像这样:
一个数组是一个对象,因此它也在堆上。那数组中的对象呢?他们拥有自己的堆空间,每个对象的地址都在数组内部。
那么,当您称呼方法时会通过什么?如果您传递对象,那么实际传递的是对象的地址。有些人可能会说地址的“价值”,有人说这只是对对象的引用。这是“参考”和“价值”支持者之间的圣战的起源。您所说的不像您了解的那样重要的是对象的地址。
创建一个字符串并在堆中分配空间,并且该字符串的地址存储在堆栈上,并给定标识符
hisname
,因为第二个字符串的地址与首先,没有创建新的字符串,也没有分配新的堆空间,但是在堆栈上创建了一个新的标识符。然后,我们调用shout()
:创建了一个新的堆栈框架,并创建了一个新的标识符,name
将创建并分配了已经存在的字符串的地址。”你说“土豆”。
I feel like arguing about pass-by-reference vs pass-by-value is not really helpful.
If you say that Java is pass-by-whatever, you are not providing a complete answer. Here is some additional information that will hopefully help you understand what actually happens in memory.
Crash course on stack/heap before we get to the Java implementation:
Values go on and off the stack in a nice orderly fashion, like a stack of plates at a cafeteria.
Memory in the heap (also known as dynamic memory) is haphazard and disorganized. The JVM just finds space wherever it can, and frees it up as the variables that use it are no longer needed.
Okay. First off, local primitives go on the stack. So this code:
results in this:
When you declare and instantiate an object. The actual object goes on the heap. What goes on the stack? The address of the object on the heap. C++ programmers would call this a pointer, but some Java developers are against the word "pointer". Whatever. Just know that the address of the object goes on the stack.
Like so:
An array is an object, so it goes on the heap as well. And what about the objects in the array? They get their own heap space, and the address of each object goes inside the array.
So, what gets passed in when you call a method? If you pass in an object, what you're actually passing in is the address of the object. Some might say the "value" of the address, and some say it's just a reference to the object. This is the genesis of the holy war between "reference" and "value" proponents. What you call it isn't as important as that you understand that what's getting passed in is the address to the object.
One String gets created and space for it is allocated in the heap, and the address to the string is stored on the stack and given the identifier
hisName
, since the address of the second String is the same as the first, no new String is created and no new heap space is allocated, but a new identifier is created on the stack. Then we callshout()
: a new stack frame is created and a new identifier,name
is created and assigned the address of the already-existing String.So, value, reference? You say "potato".
基本上,重新分配对象参数不会影响参数,例如,
将打印出
“ ha!”
而不是null
。此原因是因为bar
是baz
的值的副本,这只是对“ ha hah!”
的引用。如果是实际的参考本身,则foo
将重新定义baz
tonull
。Basically, reassigning Object parameters doesn't affect the argument, e.g.,
will print out
"Hah!"
instead ofnull
. The reason this works is becausebar
is a copy of the value ofbaz
, which is just a reference to"Hah!"
. If it were the actual reference itself, thenfoo
would have redefinedbaz
tonull
.只是为了显示对比,请比较以下 c ++ 和
在Java中,
Java只有两种类型的传递:内置类型的值,以及对象类型的指针的值。
Just to show the contrast, compare the following C++ and Java snippets:
In C++: Note: Bad code - memory leaks! But it demonstrates the point.
In Java,
Java only has the two types of passing: by value for built-in types, and by value of the pointer for object types.
Java通过值将引用引用到对象。
Java passes references to objects by value.
我不敢相信还没有人提到芭芭拉·利斯科夫(Barbara Liskov)。当她在1974年设计Clu时,她遇到了相同的术语问题,她通过共享发明了 call (也称为通过对象共享和通过对象调用)对于“在值为参考的情况下按值调用”的特定情况。
I can't believe that nobody mentioned Barbara Liskov yet. When she designed CLU in 1974, she ran into this same terminology problem, and she invented the term call by sharing (also known as call by object-sharing and call by object) for this specific case of "call by value where the value is a reference".
此问题的关键是“通过参考”的表达式中的单词参考意味着与java中 reference 的通常含义完全不同的东西。
通常在Java 中参考表示对象的参考。但是,通过参考/值通过编程语言理论通过的技术术语是在谈论引用存储可变的内存单元,这是完全不同的。
The crux of the matter is that the word reference in the expression "pass by reference" means something completely different from the usual meaning of the word reference in Java.
Usually in Java reference means a a reference to an object. But the technical terms pass by reference/value from programming language theory is talking about a reference to the memory cell holding the variable, which is something completely different.
已经有很好的答案来涵盖这一点。我想通过共享非常简单的示例(将汇编)对比,以对比Java中C ++中的传递与通过传球逐个价值之间的行为对比。
几点:
C ++通过参考示例:
Java通过“ java参考” value示例
编辑
几个人已经写了评论,这似乎表明他们不是在看我的示例,或者他们没有得到C ++例子。不确定断开连接在哪里,但是猜测C ++示例尚不清楚。我在帕斯卡(Pascal)上发布了同一示例,因为我认为逐个引用看起来更干净,但我可能错了。我可能只是让人们更加困惑。我希望不要。
在Pascal中,传递的参数称为“ VAR参数”。在下面的过程中,请注意参数为“ ptr”之前的关键字“ var”。当指针传递给此过程时,将通过参考将其传递。注意行为:当此过程将PTR设置为nil时(这是Pascal表示为null),它将为NIL设定参数 - 您无法在Java中这样做。
编辑2
的一些摘录“ Java编程语言” 撰写的 James Gosling(发明了Java)和David Holmes,以及David Holmes,第2章,第2.6.5节
他继续对物体提出相同的观点。 。 。
在同一部分结束时,他对Java的更广泛陈述仅按价值通过,而从不参考。
本书的这一部分对Java中的参数以及通过参考和逐个传递之间的区别进行了很好的解释,并且是Java的创建者。我鼓励任何人阅读它,尤其是如果您仍然不相信。
我认为这两种模型之间的区别非常微妙,除非您实际使用通过传递的编程进行了编程,否则在两个模型不同的地方很容易错过。
我希望这能解决辩论,但可能不会。
编辑3
我可能对这篇文章有些痴迷。可能是因为我觉得Java的制造商无意间传播了错误信息。如果他们没有使用“参考”一词作为指针,他们已经使用了其他东西
Dingleberry,没有问题。您可以说:“ Java以价值而不是参考来传递丁香莓”,没有人会感到困惑。
这就是只有Java开发人员对此发行的原因。他们看着“参考”一词,并认为他们确切地知道这意味着什么,因此他们甚至不费心考虑反对论点。
无论如何,我注意到一个较旧的帖子中的评论,这做出了一个我真正喜欢的气球类比。如此之多,以至于我决定将一些剪贴画粘合在一起,以制作一组动画片来说明这一点。
通过值传递引用 - 引用的更改并未反映在呼叫者的范围中,但对象的更改是。这是因为复制了引用,但是原始和副本均参考同一对象。
通过参考通过 - 没有参考的副本。单个引用由呼叫者和所调用的函数共享。引用或对象数据的任何更改都反映在呼叫者的范围中。
编辑4
我已经看到了有关此主题的帖子,该帖子描述了Java中传递参数的低级别实现,我认为这很棒且非常有用,因为它使抽象的想法变得混凝土。但是,对我而言,问题更多的是语言规范中描述的行为而不是行为的技术实施。这是从:
这意味着,Java在执行方法之前会创建传递参数的副本。像大多数在大学学习编译器的人一样,我也使用“ nofollow noreferrer”>“龙书” 这是 编译器书。它在第1章中对“逐个通话”和“引用”的“呼叫”和“呼叫”的描述很好地描述。逐个呼叫描述与Java Specs完全匹配。
早在我研究90年代的编译器时,我使用了1986年的第一版,该书将Java预先约9或10年。但是,我只是遇到了 2nd Edtiention 从2007年起实际上提到Java!第1.6.6节标记为“参数传递机制”,描述了传递的参数。这是标题为“逐个通话”下的摘录,该标题提到了Java:
编辑5
刚刚问副codilot这个问题:
我得到的答案:
There are already great answers that cover this. I wanted to make a small contribution by sharing a very simple example (which will compile) contrasting the behaviors between Pass-by-reference in c++ and Pass-by-value in Java.
A few points:
C++ pass by reference example:
Java pass "a Java reference" by value example
EDIT
Several people have written comments which seem to indicate that either they are not looking at my examples or they don't get the c++ example. Not sure where the disconnect is, but guessing the c++ example is not clear. I'm posting the same example in pascal because I think pass-by-reference looks cleaner in pascal, but I could be wrong. I might just be confusing people more; I hope not.
In pascal, parameters passed-by-reference are called "var parameters". In the procedure setToNil below, please note the keyword 'var' which precedes the parameter 'ptr'. When a pointer is passed to this procedure, it will be passed by reference. Note the behavior: when this procedure sets ptr to nil (that's pascal speak for NULL), it will set the argument to nil--you can't do that in Java.
EDIT 2
Some excerpts from "THE Java Programming Language" by Ken Arnold, James Gosling (the guy who invented Java), and David Holmes, chapter 2, section 2.6.5
He goes on to make the same point regarding objects . . .
And towards the end of the same section he makes a broader statement about java being only pass by value and never pass by reference.
This section of the book has a great explanation of parameter passing in Java and of the distinction between pass-by-reference and pass-by-value and it's by the creator of Java. I would encourage anyone to read it, especially if you're still not convinced.
I think the difference between the two models is very subtle and unless you've done programming where you actually used pass-by-reference, it's easy to miss where two models differ.
I hope this settles the debate, but probably won't.
EDIT 3
I might be a little obsessed with this post. Probably because I feel that the makers of Java inadvertently spread misinformation. If instead of using the word "reference" for pointers they had used something else, say
dingleberry, there would've been no problem. You could say, "Java passes dingleberries by value and not by reference", and nobody would be confused.
That's the reason only Java developers have issue with this. They look at the word "reference" and think they know exactly what that means, so they don't even bother to consider the opposing argument.
Anyway, I noticed a comment in an older post, which made a balloon analogy which I really liked. So much so that I decided to glue together some clip-art to make a set of cartoons to illustrate the point.
Passing a reference by value--Changes to the reference are not reflected in the caller's scope, but the changes to the object are. This is because the reference is copied, but the both the original and the copy refer to the same object.
Pass by reference--There is no copy of the reference. Single reference is shared by both the caller and the function being called. Any changes to the reference or the Object's data are reflected in the caller's scope.
EDIT 4
I have seen posts on this topic which describe the low level implementation of parameter passing in Java, which I think is great and very helpful because it makes an abstract idea concrete. However, to me the question is more about the behavior described in the language specification than about the technical implementation of the behavior. This is an exerpt from the Java Language Specification, section 8.4.1 :
Which means, java creates a copy of the passed parameters before executing a method. Like most people who studied compilers in college, I used "The Dragon Book" which is THE compilers book. It has a good description of "Call-by-value" and "Call-by-Reference" in Chapter 1. The Call-by-value description matches up with Java Specs exactly.
Back when I studied compilers-in the 90's, I used the first edition of the book from 1986 which pre-dated Java by about 9 or 10 years. However, I just ran across a copy of the 2nd Eddition from 2007 which actually mentions Java! Section 1.6.6 labeled "Parameter Passing Mechanisms" describes parameter passing pretty nicely. Here is an excerpt under the heading "Call-by-value" which mentions Java:
EDIT 5
Just asked copilot this questions:
The answer I got :
Nicely done AI!
在Java中,所有内容都是参考,因此当您有类似的东西时:
point pnt1 = new Point(0,0);
Java确实以下是:参考。因此我们可以说,在Java中,您可以通过其参考
来操纵对象。
Java java 't通过参考通过方法参数; 我将使用此站点:
程序的流程:
创建两个不同的点对象,其中有两个不同的引用。
预期输出将是:
在这一行'vass-by-value上'播放...
参考
pnt1
和pnt2
是按值传递给棘手方法的,这意味着现在您的参考pnt1
和pnt2
具有其copies
命名arg1
和arg2
arg2 .sopnt1
和arg1
点到同一对象。 (对于pnt2
和arg2
相同)在
tricky
方法中:
>点在同一位置,例如
arg1
参考。然后,您将参考arg1
移至 point 到同一位置,例如arg2
参考。最后,
arg2
将点到同一地点,例如temp
。trick> Tricky
方法的范围已经消失了,您没有访问权限更多内容:arg1
,arg2
,temp
。 当您使用“生活中”时,您对这些参考进行的所有操作都将永久影响它们的对象 point 。但重要的是, 棘手的,当您返回
main
时,您会有这种情况:现在,程序的完全执行将是:
In java everything is reference, so when you have something like:
Point pnt1 = new Point(0,0);
Java does following:reference. So we can say that in Java you manipulate object through its reference.
Java doesn't pass method arguments by reference; it passes them by value. I will use example from this site:
Flow of the program:
Creating two different Point object with two different reference associated.
As expected output will be:
On this line 'pass-by-value' goes into the play...
References
pnt1
andpnt2
are passed by value to the tricky method, which means that now yours referencespnt1
andpnt2
have theircopies
namedarg1
andarg2
.Sopnt1
andarg1
points to the same object. (Same for thepnt2
andarg2
)In the
tricky
method:Next in the
tricky
methodHere, you first create new
temp
Point reference which will point on same place likearg1
reference. Then you move referencearg1
to point to the same place likearg2
reference.Finally
arg2
will point to the same place liketemp
.From here scope of
tricky
method is gone and you don't have access any more to the references:arg1
,arg2
,temp
. But important note is that everything you do with these references when they are 'in life' will permanently affect object on which they are point to.So after executing method
tricky
, when you return tomain
, you have this situation:So now, completely execution of program will be:
java始终按价值传递,而不是通过参考
首先通过,我们需要理解逐值和通过参考的通过。
按值通过,这意味着您正在制作一个副本,以记忆所传递的实际参数的值。这是实际参数内容的副本。
通过参考(也称为地址)将其通过,这意味着存储了实际参数的地址的副本。
有时,Java可以通过参考来给予通行证的错觉。让我们使用以下示例来看看它的工作原理:
该程序的输出是:
让我们逐步了解:
众所周知,它将在堆中创建一个对象,然后将参考值返回t。例如,假设t的值为
0x100234
(我们不知道实际的JVM内部值,这只是一个示例)。将引用t传递到函数时,它不会直接传递对象测试的实际参考值,但它将创建T的副本,然后将其传递到功能。由于它是按值传递的,因此它传递了变量的副本,而不是其实际参考。由于我们说t的值为
0x100234
,因此T和F都具有相同的值,因此它们将指向同一对象。如果您使用参考f更改函数中的任何内容,它将修改对象的现有内容。这就是为什么我们获得了在功能中更新的输出
changeValue
。要更清楚地理解这一点,请考虑以下示例:
此示例是否会抛出
nullpointerexception
?不,因为它仅传递参考的副本。在通过引用传递的情况下,它可以抛出
nullpoInterException
,如下所示:Java is always pass by value, not pass by reference
First of all, we need to understand what pass by value and pass by reference are.
Pass by value means that you are making a copy in memory of the actual parameter's value that is passed in. This is a copy of the contents of the actual parameter.
Pass by reference (also called pass by address) means that a copy of the address of the actual parameter is stored.
Sometimes Java can give the illusion of pass by reference. Let's see how it works by using the example below:
The output of this program is:
Let's understand step by step:
As we all know it will create an object in the heap and return the reference value back to t. For example, suppose the value of t is
0x100234
(we don't know the actual JVM internal value, this is just an example) .When passing reference t to the function it will not directly pass the actual reference value of object test, but it will create a copy of t and then pass it to the function. Since it is passing by value, it passes a copy of the variable rather than the actual reference of it. Since we said the value of t was
0x100234
, both t and f will have the same value and hence they will point to the same object.If you change anything in the function using reference f it will modify the existing contents of the object. That is why we got the output
changevalue
, which is updated in the function.To understand this more clearly, consider the following example:
Will this throw a
NullPointerException
? No, because it only passes a copy of the reference.In the case of passing by reference, it could have thrown a
NullPointerException
, as seen below:java是一个值(按值(堆栈内存)
运作方式
让我们首先了解Java存储原始数据类型和对象数据类型的位置。
原始数据类型本身,对象引用存储在堆栈中。
对象本身存储在堆中。
这意味着,堆栈存储器存储原始数据类型,还
对象的地址。
,您始终将参考价值的位副本传递。
如果它是一种原始数据类型,则这些复制的位包含原始数据类型本身的值,这就是为什么当我们更改方法中的参数值时,它不会反映外部的更改。
如果它是 foo foo = new foo()之类的对象数据类型,则在这种情况下,在这种情况下,对象的地址的副本如文件快捷方式,假设我们有一个文本文件 abc .txt at c:\ desktop ,假设我们制作了同一文件的快捷方式,然后将其放入 c:\ desktop \ abc-shortcut 时,所以当您访问时来自 c:\ desktop \ abc.txt 和写入'stack Overflow'并关闭文件,然后再次从快捷方式打开文件,然后您写'的文件,是为程序员学习'的最大在线社区,那么总文件更改将为'堆栈溢出是程序员学习'的最大的在线社区,这意味着从您的位置无关紧要打开文件,每次我们访问同一文件时,我们都可以假设 foo 作为文件,并假设存储在 123hd7h (原始地址如 C: \ desktop \ abc.txt )地址和 234jdid (像 c:\ desktop \ abc-shortcut 的复制地址,实际上包含内部文件的原始地址)..
因此,为了更好地理解将快捷文件和感觉。
Java is a pass by value(stack memory)
How it works
Let's first understand that where java stores primitive data type and object data type.
Primitive data types itself and object references are stored in the stack.
Objects themselves are stored in the heap.
It means, Stack memory stores primitive data types and also the
addresses of objects.
And you always pass a copy of the bits of the value of the reference.
If it's a primitive data type then these copied bits contain the value of the primitive data type itself, That's why when we change the value of argument inside the method then it does not reflect the changes outside.
If it's an object data type like Foo foo=new Foo() then in this case copy of the address of the object passes like file shortcut , suppose we have a text file abc.txt at C:\desktop and suppose we make shortcut of the same file and put this inside C:\desktop\abc-shortcut so when you access the file from C:\desktop\abc.txt and write 'Stack Overflow' and close the file and again you open the file from shortcut then you write ' is the largest online community for programmers to learn' then total file change will be 'Stack Overflow is the largest online community for programmers to learn' which means it doesn't matter from where you open the file , each time we were accessing the same file , here we can assume Foo as a file and suppose foo stored at 123hd7h(original address like C:\desktop\abc.txt ) address and 234jdid(copied address like C:\desktop\abc-shortcut which actually contains the original address of the file inside) ..
So for better understanding make shortcut file and feel..
无论您使用哪种语言,参考始终是代表时的值。
获取框外视图的外部,让我们看一下汇编或一些低级别的内存管理。在CPU级别上,如果将其写入内存或CPU寄存器之一,请立即将任何内容引用到任何事物。 (这就是为什么 pointer 是一个很好的定义。它是一个值,同时具有目的)。
内存中的数据具有位置,在该位置有一个值(字节,单词,无论如何)。在组装中,我们有一个方便的解决方案,可以将名称 位置(又称变量),但是当编译代码时,汇编器简单地替换 name 在指定的位置就像您的浏览器一样,用IP地址代替域名。
直到核心,在技术上不可能在不代表任何语言的情况下对任何语言的任何内容进行引用(当它立即成为值时)。
假设我们有一个可变的foo,其位置位于内存中的第47个字节,其 value 是5。我们有另一个变量 ref2foo 位于内存中的第223个字节,其值将为47。此Ref2Foo可能是技术变量,而不是由程序明确创建。如果您只看5和47没有任何其他信息,您将仅看到两个值。
如果您将它们用作参考,则可以到达
5
我们必须旅行:这是跳伞表的工作方式。
如果我们想用Foo的值调用方法/函数/过程,则有几种可能的方法将变量传递给该方法,具体取决于 Language 及其几种方法调用模式:
在上述值以上的每个情况下,已经创建了现有值的 ,现在它正在使用接收方法来处理它。当您在方法中写“ foo”时,它要么从eax中读取,要么自动 或double删除,该过程取决于语言的工作原理和/或foo指示的类型。这是对开发人员隐藏的,直到她绕过退出过程。因此,当表示时,A 参考是A value ,因为参考是必须处理的值(在语言层面上)。
现在,我们已经将foo传递给了该方法:
foo = 9
),它只会影响本地范围,因为您拥有该值的副本。从该方法内部,我们甚至无法确定原始FOO所在的内存中的位置。foo = 11
),它可能会在全球上更改foo(取决于语言,即Java或pascal的procepture Findmin(X,Y,Z:Integer;
var m:integer);
)。但是,如果该语言允许您规避解除过程,则可以更改47
,对49
说。那时,如果您阅读了Foo,Foo似乎已经更改了,因为您已将本地指针更改为。而且,如果要在方法内修改此foo(foo = 12
),则可能会fubar fubar执行程序(aka。segfault),因为您会写入与预期的不同内存中甚至修改一个注定要保存可执行程序的区域并写入它将修改运行代码(FOO现在不在47
)。但是foo的47
的值没有在全球变化,只有该方法中的一个,因为47
也是该方法的副本。223
在该方法中,它会创建与3或4中相同的混乱。指针)但这仍然是一个本地问题,因为223被复制。但是,如果您能够解释ref2foo
(即223
),请访问并修改指向值47
,例如49
,它将影响foo 全球,因为在这种情况下,方法获得了223
的副本,但是引用47
存在一次,然后将其更改为49
将带领每个ref2foo
双重降级到错误的值。挑剔微不足道的细节,即使是逐个引用的语言也会将值传递给函数,但是这些功能知道他们必须将其用于解释目的。这种通过的参考文献是从程序员中隐藏的,因为它实际上是没有用的,术语仅是通过逐次参考。
严格的通过也是没有用的,这意味着每当我们将以数组称为参数的方法时,必须复制100 mbyte数组-价值。每种语言都会传递对这个巨大数组(作为值)的引用,并且如果可以在方法内部的本地更改该数组,或者允许该方法(如Java所做的那样)在全球修改数组(从呼叫者的视图)和几种语言允许修改参考本身的值。
因此,简而>值是参考的表示。
A reference is always a value when represented, no matter what language you use.
Getting an outside of the box view, let's look at Assembly or some low level memory management. At the CPU level a reference to anything immediately becomes a value if it gets written to memory or to one of the CPU registers. (That is why pointer is a good definition. It is a value, which has a purpose at the same time).
Data in memory has a Location and at that location there is a value (byte,word, whatever). In Assembly we have a convenient solution to give a Name to certain Location (aka variable), but when compiling the code, the assembler simply replaces Name with the designated location just like your browser replaces domain names with IP addresses.
Down to the core it is technically impossible to pass a reference to anything in any language without representing it (when it immediately becomes a value).
Lets say we have a variable Foo, its Location is at the 47th byte in memory and its Value is 5. We have another variable Ref2Foo which is at 223rd byte in memory, and its value will be 47. This Ref2Foo might be a technical variable, not explicitly created by the program. If you just look at 5 and 47 without any other information, you will see just two Values.
If you use them as references then to reach to
5
we have to travel:This is how jump-tables work.
If we want to call a method/function/procedure with Foo's value, there are a few possible way to pass the variable to the method, depending on the language and its several method invocation modes:
In every cases above a value - a copy of an existing value - has been created, it is now upto the receiving method to handle it. When you write "Foo" inside the method, it is either read out from EAX, or automatically dereferenced, or double dereferenced, the process depends on how the language works and/or what the type of Foo dictates. This is hidden from the developer until she circumvents the dereferencing process. So a reference is a value when represented, because a reference is a value that has to be processed (at language level).
Now we have passed Foo to the method:
Foo = 9
) it only affects local scope as you have a copy of the Value. From inside the method we cannot even determine where in memory the original Foo was located.Foo = 11
), it could change Foo globally (depends on the language, ie. Java or like Pascal'sprocedure findMin(x, y, z: integer;
var m: integer);
). However if the language allows you to circumvent the dereference process, you can change47
, say to49
. At that point Foo seems to have been changed if you read it, because you have changed the local pointer to it. And if you were to modify this Foo inside the method (Foo = 12
) you will probably FUBAR the execution of the program (aka. segfault) because you will write to a different memory than expected, you can even modify an area that is destined to hold executable program and writing to it will modify running code (Foo is now not at47
). BUT Foo's value of47
did not change globally, only the one inside the method, because47
was also a copy to the method.223
inside the method it creates the same mayhem as in 3. or 4. (a pointer, pointing to a now bad value, that is again used as a pointer) but this is still a local problem, as 223 was copied. However if you are able to dereferenceRef2Foo
(that is223
), reach to and modify the pointed value47
, say, to49
, it will affect Foo globally, because in this case the methods got a copy of223
but the referenced47
exists only once, and changing that to49
will lead everyRef2Foo
double-dereferencing to a wrong value.Nitpicking on insignificant details, even languages that do pass-by-reference will pass values to functions, but those functions know that they have to use it for dereferencing purposes. This pass-the-reference-as-value is just hidden from the programmer because it is practically useless and the terminology is only pass-by-reference.
Strict pass-by-value is also useless, it would mean that a 100 Mbyte array should have to be copied every time we call a method with the array as argument, therefore Java cannot be stricly pass-by-value. Every language would pass a reference to this huge array (as a value) and either employs copy-on-write mechanism if that array can be changed locally inside the method or allows the method (as Java does) to modify the array globally (from the caller's view) and a few languages allows to modify the Value of the reference itself.
So in short and in Java's own terminology, Java is pass-by-value where value can be: either a real value or a value that is a representation of a reference.
在Java中,方法参数全部按值传递:
值通过的(该方法使用时复制值或参考):
Java参数都是按 原始类型,Java行为很简单:
该值在原始类型的另一个实例中复制。
如果对象,则是相同的:
对象变量是使用“新”关键字创建的引用(仅包含对象的地址而不是原始值的MEM存储桶),并且像原始类型一样复制。
行为可能与原始类型不同:因为复制的对象变量包含相同的地址(到同一对象)。
对象的内容/成员仍可以在方法中修改,然后在外部访问后来访问,这使它幻想(包含)对象本身是通过引用传递的。
“字符串”对象似乎是一个好反面示例,说“对象是通过参考传递”的:
实际上,使用方法,您将永远无法更新值作为参数传递的字符串:
字符串对象,通过声明 final 的数组持有字符,无法修改。
只能使用“新”来代替对象的地址。
使用“新”来更新变量,由于最初按值传递并复制了该变量,因此不会从外部访问对象。
In Java, method arguments are all passed by value :
Java arguments are all passed by value (the value or reference is copied when used by the method) :
In the case of primitive types, Java behaviour is simple:
The value is copied in another instance of the primitive type.
In case of Objects, this is the same:
Object variables are references (mem buckets holding only Object’s address instead of a primitive value) that was created using the "new" keyword, and are copied like primitive types.
The behaviour can appear different from primitive types: Because the copied object-variable contains the same address (to the same Object).
Object's content/members might still be modified within a method and later access outside, giving the illusion that the (containing) Object itself was passed by reference.
"String" Objects appear to be a good counter-example to the urban legend saying that "Objects are passed by reference":
In effect, using a method, you will never be able, to update the value of a String passed as argument:
A String Object, holds characters by an array declared final that can't be modified.
Only the address of the Object might be replaced by another using "new".
Using "new" to update the variable, will not let the Object be accessed from outside, since the variable was initially passed by value and copied.
据我所知,Java只知道按价值呼叫。这意味着对于原始数据类型,您将使用副本工作,并且对于对象,您将使用对对象的引用的副本。但是我认为有一些陷阱。例如,这将行不通:
这将填充Hello World,而不是World Hello,因为在交换功能中,您使用的是对主要参考文献没有影响的配置。但是,如果您的对象不变,则可以更改它:
这将在命令行上填充Hello World。如果将StringBuffer更改为字符串,它将仅产生Hello,因为字符串是不变的。例如:
但是,您可以为这样的字符串制作包装器,这将使它能够与字符串一起使用:
编辑:我相信这也是“添加”两个字符串时使用StringBuffer的原因,因为您可以修改像字符串一样不变的对象无法使用的原始对象。
As far as I know, Java only knows call by value. This means for primitive datatypes you will work with an copy and for objects you will work with an copy of the reference to the objects. However I think there are some pitfalls; for example, this will not work:
This will populate Hello World and not World Hello because in the swap function you use copys which have no impact on the references in the main. But if your objects are not immutable you can change it for example:
This will populate Hello World on the command line. If you change StringBuffer into String it will produce just Hello because String is immutable. For example:
However you could make a wrapper for String like this which would make it able to use it with Strings:
edit: i believe this is also the reason to use StringBuffer when it comes to "adding" two Strings because you can modifie the original object which u can't with immutable objects like String is.