可以防止Java在方法中按值传递吗?

时间:2010-07-01 15:40:27

标签: java pass-by-value

Java是一种“按值传递”语言,这意味着将变量发送到方法中,将变量指向新对象,不会影响外部变量。

public void one() {

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

}

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

写“one”。

有没有办法防止这种情况发生?或者在方法中实际将s更改为“两个”的最常见解决方案或模式是什么?

11 个答案:

答案 0 :(得分:2)

无法阻止它。

您可以使用这样的通用包装器来模拟它:

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

然后按照您的意图使用它。

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";
    }
}
但是看起来很难看。我认为最好的方法是改变自己的参考:

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

并使用它

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

:)

答案 1 :(得分:1)

创建一个包含字符串的对象,然后将其传递给方法。

public class StringHolder {
    public String s;

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

然后代码看起来像:

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

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

虽然,对于上面的示例,您可以返回您想要的值:

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

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

对于String,您可以随时使用StringBuffer,这是可变的:

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

答案 2 :(得分:1)

如果s是可变对象,则可以更改其值(即其数据成员的值)。该成员也可以是String。这不能直接使用String参数,因为它是不可变的,因此“更改”它的唯一方法是将引用指向另一个对象。

答案 3 :(得分:1)

你不能通过引用传递 - 至少不是变量本身。所有参数都按值传递。但是,对象包含引用 - 并且表示为引用本身。您始终可以更改对象的内部,并保持更改。因此,发送一个数组,或创建一个包装类,或者创建自己的引用对象:

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

正如其他人所说,String无论如何都不是可变的,所以你实际上并没有在这里改变字符串,而是让变量指向另一个方向,所以它实际上并没有那么多意义只需返回新字符串。

答案 4 :(得分:1)

你不能阻止 Java传递值;这就是语言语义。

您可以通过这种或那种方式绕过它,具体取决于您想要做什么。

您可以根据传递的参数return新值:

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"

你也可以传递一些可变的东西:

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"

答案 5 :(得分:0)

字符串是不可变的......否则,你只需要调用一个方法来操作同一个对象并以某种方式改变字符串值。

我确信有很多Java类可以帮你完成这项工作,但你也可以通过创建一个包含public字段或setter / getter的封装类来自行编写。前者的一个例子是这样的:

public class EncapsulatedString
{
    public String str;

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

答案 6 :(得分:0)

1长度阵列有点难看,但完美的解决方案。无需创建多余的包装类:

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

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

这种模式在翻译旧的(例如C)代码时非常有用,其中广泛应用了传递参考。

也就是说,返回一个新的,新的值总是比改变“输入”值更容易混淆。

答案 7 :(得分:0)

创建一个包含对象并更改包装器内容的包装器:

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

答案 8 :(得分:0)

我想到的一个丑陋的解决方案是传递一个长度为1的String数组。这不是我鼓励的,但如果你觉得你想这样做的话......

  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 }

答案 9 :(得分:0)

使用可变的StringBuffer或StringBuilder。

答案 10 :(得分:-1)

Java 是一种按值传递的语言。相反 - 它是一种传递参考语言。 (传递引用并不意味着您可以将原始“指针”更改为指向C ++允许的其他位置)。 唯一通过值传递的内容是基元(intlongchar等。)
对象引用总是通过引用传递 - 所以如果你的Object能够支持对其内容的更改(例如通过getter和setter方法) - 它可以被更改。

String具体是不可变的 - 意味着其内容可能永远不会被更改。因此,对于您的特定问题,如果您希望更改局部变量's'引用的String,则需要为其提供对String对象的新实例的引用。

示例:

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

如果您使用String以外的对象 - 您可以在其上定义将为您更新其内容的setter方法。