Question

Java is a 'pass by value' language, meaning that sending in a variable into a method, pointing the variable to a new object, does not effect the outer variable.

public void one() {

String s = "one";
two(s);
System.out.println(s);

}

public void two( String s ) {
s = "two";
}

Would write "one".

Is there a way to prevent this? Or what is the most common solution or pattern to actually change s to "two" inside the method?

Was it helpful?

Solution

You can't pass-by-reference - at least not the variable itself. All parameters are passed by value. However, objects contain references - and are represented as references themselves. You can always change the insides of the object, and have the changes stick. Thus, send an array, or create a wrapper class, or make your own reference object:

class Ref<T> {
  T obj;
  public Ref(T value) {
    this.obj = value;
  }
  public void set(T value) {
    obj = value;
  }
  public T get() {
    return obj;
  }
}

As the others have said, String is not mutable anyway, so you're not actually changing the string here, but making the variable point the other way, so it does not really make that much sense not to simply return the new string.

OTHER TIPS

Is not possible to prevent it.

You can emulate it with a generic wrapper like this:

class _<T>{
    public T _;
    public _(T t ) {
        _ = t;
    }
    public String toString(){ return _.toString(); }
}

And then use it as you intended.

class GeneriWrapperDemo {
    public static void main(String [] args ) {
        _<String> one = new _<String>("One");
        two( one );
        System.out.println( one );
    }
    public static void two( _<String> s ) {
        s._ = "two";
    }
}

But looks ugly. I think the best would be to change the reference it self:

public String two( String a ) {
     return "two";
}

And use it

 String one = "one";
 one = two( one );

:)

If s were a mutable object, you could change its value (i.e. the value of its data members). And the member can be a String too. This doesn't work with a String parameter directly, as it is immutable, so the only way to "change" it is to direct the reference to a different object.

Create an object, which contains the string, then pass that into the method.

public class StringHolder {
    public String s;

    public StringHolder(String s) {
        this.s = s;
    }
}

Then the code would look like:

public void two(StringHolder sh) {
    sh.s = "two";
}

StringHolder sh = new StringHolder("one");
two(sh);
System.out.println(sh.s);

Although, for the above example, you could just return the value you want:

public String two(String s) {
    return "two";
}

String s = "one";
s = two(s);
System.out.println(s);

And for Strings, you can always use StringBuffer, which is mutable:

public void two(StringBuffer buf) {
    buf.setLength(0);
    buf.append("two");
}

You can't prevent Java from passing by value; that's the language semantics.

You can, one way or another, get around it, depending on what you want to do.

You can return a new value based on the parameter that's passed:

static String scramble(String s) {
    return s.replaceAll("(.*) (.*)", "$2, $1");
}

// then later...
String s = "james bond";
s = scramble(s);
System.out.println(s); // prints "bond, james"

You can also pass something that is mutable:

static void scramble(StringBuilder sb) {
    int p = sb.indexOf(" ");
    sb.append(", ").append(sb.substring(0, p)).delete(0, p+1);
}

// then later...
StringBuilder sb = new StringBuilder("james bond");
scramble(sb);
System.out.println(sb); // prints "bond, james"

Strings are immutable... otherwise, though, all you would have to do is call a method to operate on the same object and have that somehow change the string value.

I'm sure there are a number of Java classes that will do the job for you, but you could also roll your own simply by creating an encapsulating class with either a public field or a setter/getter. An example of the former is something like this:

public class EncapsulatedString
{
    public String str;

    public EncapsulatedString(String s)
    {
        str = s;
    }
}

Create a wrapper that contains your object and change contents of the wrapper:

public class StringWrapper {
    private String str;    
    public String getString() {
       return str;
    }
    public String setString(String str){
        this.str = str;
    }
    public String toString() {
        return str;
    }
}

public void one() {
    StringWrapper s = new StringWrapper();
    s.setString("one");
    two(w);
    // This will print "two"
    System.out.println(s);
}
public void two( StringWrapper  s ) {
    s.setString("two");
}

One ugly solution that comes to my mind is to pass around a String array of length 1. It's not something I would encourage but if you feel that you want to do it...

  1  public class One {
  2 
  3     public static void main( String[] _ ) {
  4         String[] s = {"one"};
  5         two(s);
  6         System.out.println(s[0]);
  7     }
  8 
  9     public static void two( String[] s ) {
 10         s[0] = "two";
 11     }
 12 }

1-length array is a bit ugly, but perfectly working solution. No need to create surplus wrapper classes:

public void one() {
    String[] s = new String[]{"one"};
    two(s);
    System.out.println(s[0]);
}

public void two(String[] s) {
    s[0] = "two";
}

This pattern is especially useful when translating old (e.g. C) code where pass by reference has been extensively applied.

That said, returning a new, fresh value is always less confusing than mutating the "input" value.

Use StringBuffer, or StringBuilder, which are mutable.

Java is not a pass-by-value language. On the contrary - it is a pass-by-reference language. (passing-by-reference does not mean you can change the original "pointer" to point elsewhere like C++ allows). The only things which are passed by value are primitives (int, long, char etc.)
Object references are always passed by reference - so if your Object is able to support change to its contents (e.g. via getter and setter methods) - it can be changed.

String specifically is immutable - meaning that its contents may never be changed. So for your specific question, if you want the String referred to by the local variable 's' to change you need to provide it with a reference to a new instance of a String object.

Example:

public void one()  
{
    String s = "one";
    s = two(); // Here your local variable will point to a new instance of a String with the value "two"
    System.out.println(s);
}

public String two() 
{
  return "two";
}

If you use objects other than String - you can define setter methods on them that will update their contents for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top