30

I have this very awkward 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? Let's say I want my function changeString to change the string it got to "Hello world".

0

7 Answers 7

39

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.

Sign up to request clarification or add additional context in comments.

12 Comments

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.
@anov "you can't assign a String variable to a ChangeableString" Where am I doing that?
Thanks! Actually, my func does return a value, so I cant return the new string from it. As for the second solution (with the ChangeableString), thats a good one. However, I dont want to mess up my code and add this class for only a single call. That`s really annoying, if I use Java class thet does not have some "set" function built, do I really have to use this solution of creating another container to pass it? Isnt there some workaround to pass it by &?! Thats really not nice to write a container for each class that does not have a "set" or "change" function....
@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.
@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.
|
7

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.

Comments

4

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.

Comments

2

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);
   }
}

Comments

1

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.

1 Comment

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).
0

Bill, I have a solution to your problem which uses a List as a pointer in java!

void changeString(List<String> strPointer ){
    String str = "Hello world";
    strPointer.add(0, str);
}

main(){
    LinkedList<String> list = new LinkedList<String>();
    String myStr = new String("");
    changeString(list);
    myStr = list.get(0);
    System.out.println( myStr );
}

This answer takes a little extra work to insert and get out the string from the list, however the final line will print "Hello world!"

I hope this can help others as well!

-Port Forward Podcast

Comments

0

Here's the one more solution by StringBuffer/StringBuilder worked for me.

static void changeValue(StringBuilder str){
    str.append("newValue");
}

main(){
    StringBuilder originalVal= new StringBuilder();
    changeValue(originalVal);
    System.out.println(originalVal.toString());
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.