views:

151

answers:

6

Hey guys,

I have this very akward question...

void changeString(String str){
    str = "Hello world":
}

main(){

    String myStr = new String("");
    changeString(myStr);
}

When main returns the value is still "" and not "Hello world" Why is that?

Also, how do I make it work? Lets say I want my function changeString to change the string it got to "Hello world"...?

Thanks

+3  A: 

Java uses a call by value startegy for evaluating calls.

That is, the value is copied to str, so if you assign to str that doesn't change the original value.

starblue
+5  A: 

Because the reference myStr is passed by value to the function changeString and the change is not reflected back to the calling function.

P.S : I am not a Java guy.

Prasoon Saurav
downvoter, leave a comment please.
Prasoon Saurav
I didn't downvote, but the phrase "the change is not reflected back" can be misleading. Some changes, depending on the semantics, _ARE_ reflected back. It's definitely not true that pass-by-value means that there are no side effects (and this is also the source of some beginner confusions, e.g. with passing array references and having its elements modifiable by a method).
polygenelubricants
A: 

This is because you are only passing in a reference to the String. All objects in Java are pass-by-reference.

So, str = "foo" only changes the local copy of str inside the function - and when the function returns, that local copy is gone.

Borealid
-1 This is wrong, plain wrong
NullUserException
No, all references are passed by value, which is not the same as "pass-by-reference" in a sense that is comparable to, say, C++.
Bart Kiers
Ok, so how do I make it work? Lets say I want my function changeString, change the string it got to "Hello world"...?
Yura
@Yura: Strings are immutable. You can only make the function work by putting the string into a class variable. It cannot be passed in to the function without being wrapped in another object and still be modified in a way visible to the caller.
Borealid
Thanks Borealid. :)
Yura
@Borealid The immutability of Strings is irrelevant. He would have the same problem if he were passing a (mutable) LinkedList instead of a String.
Aaron Novstrup
@anovstrup: No, he wouldn't. If he did `passed_linkedlist.add(foo)`, the change would be visible to the caller. I don't understand why this particular question has so many upvotes for incorrect information and downvotes for correct information.
Borealid
@Borealid He's not calling a method on the String. He's trying to reassign the reference to the String. It's like doing `passedLinkedList = new LinkedList();`, and it *would not* modify the original LinkedList variable outside the called method.
Aaron Novstrup
Your answer is incorrect because it claims that Java uses a pass-by-reference evaluation strategy. If that were true, the OP's original code would have worked as he expected. However, Java uses _pass-by-value-, so the code does not. http://javadude.com/articles/passbyvalue.htm
Aaron Novstrup
There's slim difference between passing a reference by value and passing an object by reference. If you work on the model that when you declare `String str;` `str` is a `String` objects, then what you get when you do `foo(str)` is pass-by-reference semantics. That's why I said "objects in Java"; primitives are indeed passed by value. I would love to see a single case where the results differ between pass-by-value with all objects being references and pass-by-reference with all objects being values. This is just nomenclature.
Borealid
@Borealid, Java does not pass objects, only addresses (references to objects) and primitives are passed (all by value!). You may very well meant to explain it correctly, but calling this "pass-by-reference" is not only wrong, but leads to confusion.
Bart Kiers
Aaron Novstrup
+8  A: 

Everyone explained why it doesn't work, but nobody explained how to make it work. Your easiest option is to use:

String changeString() {
    return "Hello world";
}

main() {

    String myStr = new String("");
    myStr = changeString();
}

Although the method name is a misnomer here. If you were to use your original idea, you'd need something like:

void changeString(ChangeableString str) {
    str.changeTo("Hello world");
}

main() {

    ChangeableString myStr = new ChangeableString("");
    changeString(myStr);
}

Your ChangeableString class could be something like this:

class ChangeableString {
    String str;

    public ChangeableString(String str) {
        this.str = str;
    }

    public void changeTo(String newStr) {
        str = newStr;
    }

    public String toString() {
        return str;
    }
}

A quick lesson on references:

In Java method everything is passed by value. This includes references. This can be illustrated by these two different methods:

void doNothing(Thing obj) {
    obj = new Something();
}

void doSomething(Thing obj) {
    obj.changeMe();
}

If you call doNothing(obj) from main() (or anywhere for that matter), obj won't be changed in the callee because doNothing creates a new Thing and assigns that new reference to obj in the scope of the method.

On the other hand, in doSomething you are calling obj.changeMe(), and that dereferences obj - which was passed by value - and changes it.

NullUserException
maybe nitpicky, but your second solution won't work because String is a final class (you can't assign a String variable to a ChangeableString). It would probably help the OP to see how you would have to define ChangeableString.
Aaron Novstrup
@anov "you can't assign a String variable to a ChangeableString" Where am I doing that?
NullUserException
Yura
@Yura Strings are immutable in Java, AFAIK there's no workaround for that.
NullUserException
@NullUserException Your original solution had `String myStr = new ChangeableString("");`. Looks good now.
Aaron Novstrup
Thanks a lot @NullUserException. I think I found a workaround, I am using a char[] instead of String.
Yura
@Yura I guess the real question we all should have been asking is _why_ you want to change the `myStr` reference. It might be better to make it a member variable of the class that contains your `main()` method.
Aaron Novstrup
@avon It was copy and pasted, I forgot to change that.
NullUserException
I'd advise against using a `char[]` if you're just doing it to avoid using the idioms of the language you're coding in.
Aaron Novstrup
Yura
@Yura It's hard to help without seeing a more representative code sample, but from what your saying it sounds like your code needs to be refactored. Using a `char[]` (or a `String[]` that just contains one `String`!) is just a way to hack around the issue rather than correcting it. I understand the temptation to fall back on C++ idioms if that's what you're used to, but it's going to impede your progress in learning the new language.
Aaron Novstrup
@avin thank you very much. The char[] works for me and this is a very minor part of the code I dont want to waste any more time refactoring. It just doe not worth it. Thank you a lot thanks to everybody, I got it :))
Yura
A: 

If the changing of your String happens very often you could also assign a StringBuffer or StringBuilder to your variable and change its contents and only convert it to a String when this is needed.

Johannes Wachter
A: 

Expanding a bit on NullUserException's excellent answer, here's a more general solution:

public class Changeable<T> {
   T value;

   public Changeable(T value) {
      this.value = value;
   }

   public String toString() {
      return value.toString();
   }

   public boolean equals(Object other) {
      if (other instanceof Changeable) {
         return value.equals(((Changeable)other).value);
      } else {
         return value.equals(other);
      }
   }

   public int hashCode() {
      return value.hashCode();
   }
}

Yura's original code can then be rewritten as:

void changeString(Changeable<String> str){
   str.value = "Hello world":
}

void main() {
   Changeable<String> myStr = new Changeable<String>("");
   changeString(myStr);
}

And, just for fun, here it is in Scala:

class Changeable[T](var self: T) extends Proxy;

object Application {
   def changeString(str: Changeable[String]): Unit = {
      str.self = "Hello world";
   }

   def main(): Unit = {
      val myStr = new Changeable("");
      changeString(myStr);
   }
}
Aaron Novstrup