通过参考在Java中传递一个字符串?(Passing a String by Reference i

2019-06-18 10:34发布

我习惯做下面C

void main() {
    String zText = "";
    fillString(zText);
    printf(zText);
}

void fillString(String zText) {
    zText += "foo";
}

而输出是:

foo

然而,在Java中,这似乎并没有工作。 我想是因为String对象被复制 ,而不是通过了参考 。 我以为丝线对象,它们总是通过引用传递。

这里发生了什么?

Answer 1:

你有三个选择:

  1. 使用StringBuilder:

     StringBuilder zText = new StringBuilder (); void fillString(StringBuilder zText) { zText.append ("foo"); } 
  2. 创建一个容器类并通过容器的方法的一个实例:

     public class Container { public String data; } void fillString(Container c) { c.data += "foo"; } 
  3. 创建磁盘阵列:

     new String[] zText = new String[1]; zText[0] = ""; void fillString(String[] zText) { zText[0] += "foo"; } 

从性能上看,StringBuilder的通常是最好的选择。



Answer 2:

在Java中没有什么是按引用传递 。 一切都按值传递 。 对象引用是按值传递。 此外字符串是不可改变的 。 所以,当你追加到传递的字符串,你只是得到一个新的String。 你可以使用一个返回值,或通过一个StringBuffer来代替。



Answer 3:

正在发生的事情是,基准是按值,即通过时,引用的副本被传递。 在Java中没有什么是按引用传递,并且因为字符串是不变的,即赋值创建一个新的字符串对象引用的副本现在指向。 最初的参考仍指向空字符串。

这对于任何对象相同,即,将其设置为在一个方法的新值。 下面的例子只是让正在发生的事情更明显,但连接字符串是真正的同样的事情。

void foo( object o )
{
    o = new Object( );  // original reference still points to old value on the heap
}


Answer 4:

java.lang.String中是不可变的。

我恨粘贴网址,但https://docs.oracle.com/javase/10/docs/api/java/lang/String.html供您阅读和理解,如果你在Java的土地是是必不可少的。



Answer 5:

目的通过引用传递,基元值传递。

字符串不是原始的,它是一个对象,并且它是对象的一种特殊情况。

这是节省内存的目的。 在JVM中,有一个字符串池。 对于创建的每个字符串,JVM会尝试看看,如果相同的字符串在字符串池中存在,并指出,如果已经有一个。

public class TestString
{
    private static String a = "hello world";
    private static String b = "hello world";
    private static String c = "hello " + "world";
    private static String d = new String("hello world");

    private static Object o1 = new Object();
    private static Object o2 = new Object();

    public static void main(String[] args)
    {
        System.out.println("a==b:"+(a == b));
        System.out.println("a==c:"+(a == c));
        System.out.println("a==d:"+(a == d));
        System.out.println("a.equals(d):"+(a.equals(d)));
        System.out.println("o1==o2:"+(o1 == o2));

        passString(a);
        passString(d);
    }

    public static void passString(String s)
    {
        System.out.println("passString:"+(a == s));
    }
}

/ *输出* /

a==b:true
a==c:true
a==d:false
a.equals(d):true
o1==o2:false
passString:true
passString:false

所述==正在检查存储器地址(参考),以及.equals正在检查的内容(值)



Answer 6:

字符串是Java中的不可变对象。 您可以使用StringBuilder类做你要完成的工作如下:

public static void main(String[] args)
{
    StringBuilder sb = new StringBuilder("hello, world!");
    System.out.println(sb);
    foo(sb);
    System.out.println(sb);

}

public static void foo(StringBuilder str)
{
    str.delete(0, str.length());
    str.append("String has been modified");
}

另一个选择是创建一个字符串作为变量范围(高度气馁)一类如下:

class MyString
{
    public String value;
}

public static void main(String[] args)
{
    MyString ms = new MyString();
    ms.value = "Hello, World!";

}

public static void foo(MyString str)
{
    str.value = "String has been modified";
}


Answer 7:

Java中的所有参数都按值传递。 当你传递一个String的函数,这是传递的值一个String对象的引用,但你不能修改的参考和底层String对象是不可改变的。

分配

zText += foo;

相当于:

zText = new String(zText + "foo");

即,(局部地)重新分配参数zText作为新的参考,它指向一个新的存储位置,其中,是一种新的String包含的原始内容zText"foo"追加。

原始对象没有被修改,和main()方法的局部变量zText仍然指向原始(空)的字符串。

class StringFiller {
  static void fillString(String zText) {
    zText += "foo";
    System.out.println("Local value: " + zText);
  }

  public static void main(String[] args) {
    String zText = "";
    System.out.println("Original value: " + zText);
    fillString(zText);
    System.out.println("Final value: " + zText);
  }
}

打印:

Original value:
Local value: foo
Final value:

如果要修改字符串,你可以注意使用StringBuilder ,否则一些容器(数组或AtomicReference ,让您的指针间接的附加级别或自定义容器类)。 另外,刚刚返回新值并将其分配:

class StringFiller2 {
  static String fillString(String zText) {
    zText += "foo";
    System.out.println("Local value: " + zText);
    return zText;
  }

  public static void main(String[] args) {
    String zText = "";
    System.out.println("Original value: " + zText);
    zText = fillString(zText);
    System.out.println("Final value: " + zText);
  }
}

打印:

Original value:
Local value: foo
Final value: foo

这可能是在一般情况下,最类似Java的解决方案- “青睐不变性”看到有效的Java项目

如前所述,虽然StringBuilder会经常给你更好的性能-如果你有很多附加的事,特别是在循环中的,使用StringBuilder

但是,试图通过围绕不可改变Strings ,而不是可变StringBuilders如果你能-你的代码会更易于阅读和更容易维护。 考虑对你的参数final ,并配置你的IDE时,重新分配方法的参数为新值警告你。



Answer 8:

答案很简单。 Java中的字符串是不可变的。 因此,它的使用像“最终”改性剂(或者在C / C“常量” ++)。 所以,一旦分配,你不能像你这样的方式改变它。

您可以更改值到串点,但你不能改变此字符串当前所指向的实际值。

IE浏览器。 String s1 = "hey" 。 你可以让s1 = "woah" ,这是完全正常的,但你不能真正改变字符串的潜在价值(在这种情况下:“哎”)是别的东西一旦其使用plusEquals,分配等(即。 s1 += " whatup != "hey whatup"

要做到这一点,使用StringBuilder或StringBuffer的类或其他可变容器,然后只需要调用的ToString()将对象转换回字符串。

注意:字符串经常被用来作为哈希键,因此这就是为什么他们是不可改变的部分原因。



Answer 9:

字符串是Java中的特殊类。 它是线程安全的,这意味着“一旦一个String实例被创建,字符串实例的内容永远不会改变。”

这是怎么回事了

 zText += "foo";

首先,Java编译器会得到zText String实例的值,然后创建其值zText追加“foo”的一个新的String实例。 所以,你知道为什么实例,以不改变zText点。 这完全是一个新的实例。 事实上,即使是字符串“foo”是一个新的String实例。 因此,对于这一说法,Java将创建两个String实例,一个是“富”,另一种是zText的值追加“富”。 规则很简单:String对象的值将不会被改变。

对于方法fillString,你可以使用一个StringBuffer为参数,或者你可以改变它是这样的:

String fillString(String zText) {
    return zText += "foo";
}


Answer 10:

字符串是不可变 Java中。



Answer 11:

这个作品用StringBuffer

public class test {
 public static void main(String[] args) {
 StringBuffer zText = new StringBuffer("");
    fillString(zText);
    System.out.println(zText.toString());
 }
  static void fillString(StringBuffer zText) {
    zText .append("foo");
}
}

更妙的是使用StringBuilder

public class test {
 public static void main(String[] args) {
 StringBuilder zText = new StringBuilder("");
    fillString(zText);
    System.out.println(zText.toString());
 }
  static void fillString(StringBuilder zText) {
    zText .append("foo");
}
}


Answer 12:

字符串是在java中不可改变的。 你不能修改/变化,现有的字符串文字/对象。

字符串s = “你好”; S = S + “喜”;

在此之前的参考s被新refernce指点下更换看重“HelloHi”。

然而,对于将可变性我们的StringBuilder和StringBuffer。

StringBuilder的S =新的StringBuilder(); s.append( “你好”);

该追加新价值“嗨”到同一refernce秒。 //



Answer 13:

亚伦Digulla有最好的答案为止。 他的第二个选项的一个变化是使用的公郎库版本3+包装或容器类MutableObject:

void fillString(MutableObject<String> c) { c.setValue(c.getValue() + "foo"); }

保存容器类的声明。 缺点是公地郎LIB的依赖。 但LIB有相当多有用的功能,几乎任何较大的项目我已经在使用它的工作的。



Answer 14:

对于由在Java引用传递对象(包括字符串),则可能将它作为周围适配器的构件。 有一个通用的解决方案是在这里:

import java.io.Serializable;

public class ByRef<T extends Object> implements Serializable
{
    private static final long serialVersionUID = 6310102145974374589L;

    T v;

    public ByRef(T v)
    {
        this.v = v;
    }

    public ByRef()
    {
        v = null;
    }

    public void set(T nv)
    {
        v = nv;
    }

    public T get()
    {
        return v;
    }

// ------------------------------------------------------------------

    static void fillString(ByRef<String> zText)
    {
        zText.set(zText.get() + "foo");
    }

    public static void main(String args[])
    {
        final ByRef<String> zText = new ByRef<String>(new String(""));
        fillString(zText);
        System.out.println(zText.get());
    }
}


文章来源: Passing a String by Reference in Java?