我习惯做下面C
:
void main() {
String zText = "";
fillString(zText);
printf(zText);
}
void fillString(String zText) {
zText += "foo";
}
而输出是:
foo
然而,在Java中,这似乎并没有工作。 我想是因为String
对象被复制 ,而不是通过了参考 。 我以为丝线对象,它们总是通过引用传递。
这里发生了什么?
Answer 1:
你有三个选择:
使用StringBuilder:
StringBuilder zText = new StringBuilder (); void fillString(StringBuilder zText) { zText.append ("foo"); }
创建一个容器类并通过容器的方法的一个实例:
public class Container { public String data; } void fillString(Container c) { c.data += "foo"; }
创建磁盘阵列:
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:
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?