This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 6 years ago.
Since java is pass by value.In below code we are passing a value to appendStringMethod not a reference, then why in main method we get HelloWorld not just Hello after calling appendStringMethod() in main.
public class test {
public static void main(String args[]) {
StringBuilder str = new StringBuilder("Hello");
appendStringMethod(str);
System.out.println(str);
}
static void appendStringMethod(StringBuilder s) {
s.append("World");
}
}
However in below code, values are not swapped.
public class Mock {
public static void main(String args[]) {
StringBuilder str1 = new StringBuilder("Hello");
StringBuilder str2 = new StringBuilder("World");
swap(str1, str2);
System.out.println(str1);
System.out.println(str2);
}
static void swap(StringBuilder s1, StringBuilder s2) {
StringBuilder s= s1;
s1=s2;
s2=s1;
}
}
It's because the reference to the StringBuilder is passed by value. You can add characters and they will be in the instance after the method returns. This in the end acts like a pass by reference. It works similarly with the Collection classes (List, Map,...), as well as your own classes.
In the case of primitive types (int,...), 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 pointers that holds the Object’s address so the references are copied. The only exception I can think of are String Objects as the characters are stored in an array declared final so that it cannot be modified.
While Java is technically pass by value for everything, as spoken about here, It's best not to think of it like that.
When passing an instance of a class into a method, you're really passing the reference of the object by value.
StringBuilder str = new StringBuilder("Hello");
appendStringMethod(str);
In this code, you are passing a reference to the StringBuilder instance into the appendStringMethod by value.
As a result, str will become "HelloWorld" once the method has been called.
Note: This doesn't apply to primitives such as int and char. Since they are not actual objects, they won't have a reference. This means they will be passed by value in the "expected" way.
In java we pass by value of reference. Have a look at a following example:
public void foo(Integer i) {
i = new Integer(1000);
}
public void bar(Integer i) {
i++;
}
Integer n = new Integer(2000);
foo(n);
bar(n);
System.out.println(n.toString());
I believe that much of the confusion on this issue has to do with the
fact that different people have different definitions of the term
"reference". People coming from a C++ background assume that
"reference" must mean what it meant in C++, people from a C background
assume "reference" must be the same as "pointer" in their language,
and so on. Whether it's correct to say that Java passes by reference
really depends on what's meant by "reference".
--first comment
Related
I started with java a couple of weeks ago. Before that i had multiple years working with c/c++ on embedded targets and with c# with UI Stuff on Win PCs.
I got this very simple example:
public class StreamProcessing {
public static void main(String[] args) {
Stream stream = new Stream(); //after this line: Stream string empty
StreamFiller.fillStream(stream); //after this line: Stream string not empty any more
StreamPrinter.printStream(stream);
}
}
I'd expect that whatever StreamFiller.fillStream() does, the argument is copied. However it looks like fillStream is modifying the actual stream object itself.
The Stream class basically contains a string
public class Stream {
private String content = "";
int index = 0;
public char readChar() {
if (index < content.length()) {
return content.charAt(index++);
} else {
return 0;
}
}
public void writeString(String str) {
content += str;
}
}
The Streamfiller should modify it's stream copy but not the original reference
public class StreamFiller {
public static void fillStream( Stream stream ) {
stream.writeString( "This is a" );
stream.writeString( " stream." );
}
}
Please correct me if I'm wrong, but since the actual text of the string class is allocated on the heap, both the StreamProcessing () Stream object and the (supposed copied) local object of fillStream() point to the same address on the heap (yeah i now it's not an actual memory address like in c/c++ but some unique object identifier)
So is my assumption correct? Non trivial objects (aka objects allocated on the heap) are passed by reference?
thx for your help :)
The Java language does not let you make heap / stack distinction in your code the way C and C++ do.
Instead, it divides all data types in to two groups:
Primitive types:
These are simple built in numerical types such as int, double or boolean (not a numerical type in Java).
Note that String is not such a type!
Object types:
If it is a class, it is an object type. This goes for built in types such as String and for user defined types such as your Stream class.
For these types, all you ever see is a reference, whether you are looking at a local variable, class member, instance member, or function parameter.
Lets look at a simple example:
public class A {
public int a;
public static void main(String [] args) {
A var1 = new A();
A var2 = var1;
var1.a = 42;
System.out.println("var2.a = " + var2.a);
}
}
If you compile and run this example it will print 42.
In C++ the line A var2 = var1; would have invoked a copy constructor and created a new object but in Java there is no such thing. If you want a copy, you need to invoke clone method explicitly.
What is held in var1 and copied to var2 is just a reference.
So both vars "point" to the same object.
And again - it does not matter if the class is trivial or not. Even if a class is completely empty, you will still only be given and work with a reference to any object of this class.
As for the primitive types mentioned earlier, Java has wrapper classes such as Integer and Boolean for them.
You might want to read about "boxing" and "unboxing".
One more thing to note is that some types are immutable - that is, they do not provide a way to change their data once created.
String in Java is an immutable type, but it is also a bit different from any other type.
It has special privileges.
While Java does not support operator overloading like C++ does, for String type the language does provide a special + operator that preforms string concatenation.
How ever, since String objects are immutable, any concatenation operation will create a brand new String object, even one like this:
String a = "Hello";
a = a + " world!";
This creates a new string "Hello world" and stores the reference to it in a, leaving the reference to old "Hello" string to be garbage collected at some future point.
Even though in Java everything is passed by value, there is a difference between how primitive data types (such as int, char and boolean) and how reference data types are passed to a method.
When passing the value of a primitive data type, this value can only be changed in the scope of the particular method. When passing the value of a reference data type, the reference will remain the same but the value will change globally (or in whatever scope the object was initialised).
See also this for more information: https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 4 years ago.
I've read a gazillion times that in Java, arguments passed to methods cannot be modified by the methods. Nonetheless, I find I can modify objects I create as opposed to Java Objects. Consider the following code:
// My Integer Object
class MyInteger {
Integer val;
}
// Change Java Object
public void test1() {
Integer intval; // Integer object
intval = 123;
setInteger( intval ); // THIS DOESN'T WORK
TTY.putR( "Integer Object="+intval);
}
// Change My Object
public void test2() {
MyInteger myInt; // MyInteger object
myInt = new MyInteger();
myInt.val = 456;
setMyInteger( myInt ); // THIS WORKS!
TTY.putR( "MyIntegerObject=" + myInt.val );
}
// Set an Integer object
public void setInteger( Integer val) {
val = 888;
}
// Set a MyInteger object
public void setMyInteger( MyInteger myint) {
myint.val = 999;
}
test1 doesn't work as I have been warned. But test2 works just fine. AFAIK, both are objects and are passed by reference. So how come one works and the other doesn't? (Note: TTY is my print function)
You have either read things that were wrong, or misunderstood what you've been told.
If you pass 'a' to a java method, you cannot have the method change 'a' to be something other than 'a'. However, you can modify 'a'.
In other words, you cannot create an object of the same class as 'a' and return that in place of 'a'. The only way you can return an object created by the method is either to have a place to put a reference to that new object within an object passed to the method, or to return it as the return value from the method.
The best way I've seen this explained:
You pass an object A pointing to a memory address P.
A ===> P
When you modify A by doing A.foo = bar, A is still pointing to P, so the object at P has its property foo changed. However, let's say you want to completely reassign A, and so do A = new MyCoolObject(). This means
P_New <=== A ==/=> P
So when you modify A by doing A.foo = bar, A is no longer pointing to P, so the object at P_New has its property foo changed, but the object at P remains unchanged. This means when you exit the method and go back to whatever parent called the method, A will be completely unchanged.
Disclaimer: I saw this on another Stack Overflow article probably 5 years ago, and am too lazy to find it. If you're reading this right now and you're the person who wrote this, thanks, and forgive my casual plagiarism.
I think you are confused by pass-by-reference vs. pass-by-value. Read this to help clear it up.
You might also have misinterpreted what you've read. A mutable Object can be mutated anywhere -- where it is created or by a method it is passed to.
Good luck.
Because MyInteger the val is a public variable. So ANYONE can modify it.
// Change MyInteger object
public void setMyInteger( MyInteger val) {
val.val = 999; // ACCESING TO A PUBLIC VAR and SETTING IT
}
// Change an Integer object
public void setInteger( Integer val) {
val = 888; // Accesing to the value of the Variable and not modifing it
}
Java is a pass by value language. When you invoke any method with argument it creates new variable and you are changing this variable.
You can look at this also,
Is Java "pass-by-reference" or "pass-by-value"?
This is my code :
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
String str = new String("this is a text");
System.out.println(str);
getThis(str);
System.out.println(str);
}
private static void getThis(String str) {
str = "text changed";
}
}
and the output is :
this a text
this a text
I want str change after the getThis method called.
I know I should pass str by reference, and I know that this can be done by declaring the str as static and out of the main method and then call it in the method like this Main.str. But is it the correct way and standard way to pass by reference?
Java is not pass by reference, it's always pass by value. And for references.
It's passing references as values to the caller. You can do it by returning the String value from getThis() method and assigned to the same variable
public class Main {
public static void main(String[] args) {
String str = new String("this is a text");
System.out.println(str);
str = getThis();
System.out.println(str);
}
private static String getThis() {
return "text changed";
}
}
As others have stated Java is always pass by value with the slight caveat that when you pass in objects (like String) you are passing the value of a Reference to an object on the heap.
In your example, assignment has no effect outside the method and since Strings are immutable you can't really do much. If you passed in a StringBuilder then you could mutate the state of the object on the heap.
More generally instead of passing in an Object x you can pass in a wrapper object that contains a set method. Java provides an AtomicReference which allows you to do this.
In java, "references to objects are passed by value". So, any
reference to a non-primitive object that you pass will be directly
used and changes will be reflected in the original object.
Also, as a side note, Strings are immutable, so, you
will get a new String if you try to change it (Strings cannot be changed), the original one will not be changed.
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
public void otherMethod(){
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("abc");
list.add("abc");
someOtherMethod(list);
System.out.println(list.size());
}
public void someOtherMethod(List<String> list){
list.add("abc");
}
Invoking otherMethod prints 4.
where as
public void otherMethod(){
int a = 10
someOtherMethod(a);
System.out.println(a);
}
public void someOtherMethod(int a){
a = 11;
}
prints 10;
How are the two different. Aren't both local variables? Does sending list reference work in a different way? Please help me understand how the two scenario differ?
Before downvoting please make me understand why this below one also prints 10?
public void otherMethod(){
Long a = new Long(10);
someOtherMethod(a);
System.out.println(a);
}
public void someOtherMethod(Long a){
a = 11;
//or a= new Long(11);
}
In fact conceptually they are not different, in both cases a copy of the original value is passed in as an argument to the method. The thing is that in the first case you have a complex/composite structure of some sort so you pass in a reference copy which is different from the original reference but which still points to the original structure/object.
In the second case you pass in a copy of an int and so the method just operates on the copied int. Unlike that in the first case the method operates directly on the original structure through that copy of the reference (which it receiver from the caller).
Now, in the case of Integer and Long, you work on the original objects through a copied reference. The thing is that you cannot do much on the original object as these classes are immutable e.g. they don't have methods Integer.increment(int n) or Long.increment(long n) which change the original objects by incrementing their values. It would be same if we talk about String (which is immutable) but not the same if we talk about StringBuilder (as the latter is mutable).
public void someOtherMethod(Long a){
a = 11;
//or a= new Long(11);
}
In this example you direct the copied reference to a new object (11)
but the caller still has the original reference which still points
to the same old object (10). You have no way of changing the original
object (from within the called method) just because Long is immutable.
If it wasn't, you would be able e.g. to increment it e.g. by calling
a.increment(1). If that was possible, this is different: you're not
directing the copied reference to a new object, you're using it to call
a method on the original object.
Remember, Java is pass-by-value (always) but certain
differences like these make people confused sometimes.
int are not Objects in Java, so no a is not a reference.
private static void changeString(String s) {
s = new String("new string");
}
public static void main(String[] args) {
String s = new String("old string");
changeString(s);
System.out.println(s); // expect "new string"
}
How could I make the output of "new string" happen with s as the only argument to method changeString?
thanks.
In Java arguments are passed by value, object arguments pass a reference to the object, this means that you can change the reference of the argument, but that does not change the object you passed the reference to. You have two possibilities, return the new object (preferred) or pass reference to a container that can receive the new reference (collection, array, etc.) For example:
private static String changeStringAndReturn(String s) {
return new String("new string");
}
private static void changeStringInArray(String[] s) {
if (null != s && 0 < s.length) {
s[0] = new String("new string");
}
}
References in Java are passed by value, so even if you modify the reference inside the function, changes won't be reflected back to the calling function because what you modify inside the function is just a copy of the original reference not the original reference itself.
But you can return the new string from your changeString method instead of trying to modify the reference there(inside the function) itself.
Only if you make the function
private static void changeString(String[] s) {
s[0] = new String("new string");
}
String are immutable, and Java has no concept of a 'pointer-to-a-reference' as a first class datatype. If you don't like the above, you can make a little class containing a single String field.
You can, of course, return the new string from your changeString method instead of trying to change it in place.
Alternately, you can create an object that wraps or contains a string, and pass that in. The ChangeString method would change the string that was internal to your object, and the main method would still be holding a reference to that object.
Otherwise, you can't do this. String is immutable, and java always passes objects as a value that is a pointer to a particular object. Change where you're pointing, and you aren't referencing the same object anymore.
Strings are immutable in Java and parameters are passed by value so you can't change them (there is not equivalent to ref in C#). You can pass in a StringBuilder and change it's contents just as easily.
A: You can't, in Java object references are pass by value.
If you really need to, you can create a wrapper like this and use it the way you expected:
private static void changeString( _<String> str) {
str.s("new string");
}
public static void main(String[] args) {
_<String> s = new _<String>("old string");
changeString(s);
System.out.println(s); // prints "new string"
}
I know this is old, but, just for posterity, most of this is mostly wrong.
In Java, non-primitives are passed by reference. Primitives (boxed and unboxed) are passed by value.
To directly answer OP, you're getting a reference to the actual String you passed. However, as #bmarguilies correctly pointed out - Strings are immutable in Java. Any assignment to a String creates a copy, then assigns the newly-assembled copy to the reference.
This is not possible in Java as everything in Java is passed by value. In this case where the argument is an object reference it is the value of the reference that is passed into the method, not the reference itself.
Java does not allow out parameters like C#, so you will not be able to achieve this as such.
Its ugly but you could change the String to global static:
private static String s;
private static void changeString(String t) {
if(s.equals(t))
s = new String("new string");
}
public static void main(String[] args) {
s = new String("old string");
changeString(s);
System.out.println(s); // expect "new string"
}