Passando uma String por Referência em Java?

Eu estou acostumado a fazer o seguinte em C :

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

E a saída é:

 foo 

No entanto, em Java, isso não parece funcionar. Eu suponho porque o object String é copiado em vez de passado por referenciado . Eu pensei que Strings eram objects, que são sempre passados ​​por referência.

O que está acontecendo aqui?

Você tem três opções:

  1. Use um StringBuilder:

     StringBuilder zText = new StringBuilder (); void fillString(StringBuilder zText) { zText.append ("foo"); } 
  2. Crie uma class de contêiner e passe uma instância do contêiner para o seu método:

     public class Container { public String data; } void fillString(Container c) { c.data += "foo"; } 
  3. Crie uma matriz:

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

Do ponto de vista do desempenho, o StringBuilder é geralmente a melhor opção.

Em Java nada é passado por referência . Tudo é passado por valor . Referências de objects são passadas por valor. Além disso, as strings são imutáveis . Então, quando você acrescentar à String passada, você acaba de obter uma nova String. Você poderia usar um valor de retorno ou passar um StringBuffer em seu lugar.

O que está acontecendo é que a referência é passada por valor, ou seja, uma cópia da referência é passada. Nada em java é passado por referência e, como uma string é imutável, essa atribuição cria um novo object de string para o qual a cópia da referência agora aponta. A referência original ainda aponta para a string vazia.

Isso seria o mesmo para qualquer object, ou seja, definindo-o como um novo valor em um método. O exemplo abaixo apenas torna o que está acontecendo mais óbvio, mas concatenar uma string é realmente a mesma coisa.

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

java.lang.String é imutável.

Eu odeio colar URLs, mas https://docs.oracle.com/javase/10/docs/api/java/lang/String.html é essencial para você ler e entender se estiver em java-land.

objects são passados ​​por referência, primitivos são passados ​​por valor.

A string não é primitiva, é um object e é um caso especial de object.

Isto é para fins de economia de memory. Na JVM, há um pool de cadeias. Para cada cadeia criada, a JVM tentará ver se a mesma cadeia existe no conjunto de cadeias de caracteres e apontará para ela se já existir uma cadeia.

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

/ * SAÍDA * /

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

o == está verificando o endereço de memory (referência) e o .equals está verificando o conteúdo (valor)

String é um object imutável em Java. Você pode usar a class StringBuilder para executar o trabalho que está tentando realizar, da seguinte maneira:

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

Outra opção é criar uma class com uma String como uma variável de escopo (altamente desencorajada) da seguinte maneira:

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

Strings são passadas por referência (bem, estritamente falando, como observa Ed Swangren, uma referência à string é passada por valor ), mas elas são imutáveis.

 zText += foo; 

é equivalente a

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

Ou seja, ele modifica a variável (local) zText tal forma que agora aponta para um novo local de memory, no qual é uma String com o conteúdo original de zText , com "foo" anexado. O object original não é modificado e a variável local do método main() zText ainda aponta para a string original (vazia).

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

impressões

 Original value: Local value: foo Final value: 

Se você quiser modificar a seqüência de caracteres, você pode, como observado, usar StringBuilder ou outro contêiner (uma matriz ou uma class de contêiner personalizada) que fornece um nível adicional de indireção de ponteiro. Como alternativa, basta retornar o novo valor e atribuí-lo:

 class StringFiller2 { static StringfillString(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); } } 

impressões

 Original value: Local value: foo Final value: foo 

Esta é provavelmente a solução mais parecida com Java no caso geral – veja o item Effective Java “Favorabilidade de imutabilidade”.

Como observado, no entanto, o StringBuilder frequentemente lhe dará melhor desempenho – se você tiver muito apelo para fazer, particularmente dentro de um loop, use o StringBuilder .

Mas tente passar Strings imutáveis ​​em vez de StringBuilders mutáveis, se puder – seu código será mais fácil de ler e mais sustentável. Considere tornar seus parâmetros final e configurar seu IDE para avisá-lo quando você reatribuir um parâmetro de método a um novo valor.

String é uma class especial em Java. É o Salvamento de Encadeamento, que significa “Uma vez que uma instância de Cadeia de caracteres é criada, o conteúdo da instância de Cadeia de caracteres nunca será alterado”.

Aqui está o que está acontecendo

  zText += "foo"; 

Primeiro, o compilador Java obterá o valor da instância zText String e, em seguida, criará uma nova instância String cujo valor é zText anexando “foo”. Então você sabe por que a instância para a qual o zText aponta não foi alterada. É totalmente um novo exemplo. Na verdade, até String “foo” é uma nova instância de String. Portanto, para esta declaração, Java criará duas instâncias String, uma é “foo”, outra é o valor de zText append “foo”. A regra é simples: o valor da instância String nunca será alterado.

Para o método fillString, você pode usar um StringBuffer como parâmetro, ou você pode alterá-lo assim:

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

A resposta é simples. Em java strings são imutáveis. Portanto, é como usar o modificador ‘final’ (ou ‘const’ em C / C ++). Então, uma vez atribuído, você não pode mudá-lo da maneira que você fez.

Você pode alterar o valor para o qual uma string aponta, mas você NÃO pode alterar o valor real para o qual esta string está apontando no momento.

Ie. String s1 = "hey" . Você pode fazer s1 = "woah" , e isso é totalmente ok, mas você não pode realmente alterar o valor subjacente da string (neste caso: “hey”) para ser outra coisa, uma vez que é atribuído usando plusEquals, etc. . s1 += " whatup != "hey whatup" ).

Para fazer isso, use as classs StringBuilder ou StringBuffer ou outros contêineres mutáveis, e apenas chame .toString () para converter o object de volta para uma string.

Nota: As cordas são frequentemente usadas como chaves de hash, portanto, isso é parte da razão pela qual elas são imutáveis.

As cordas são imutáveis em Java.

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

Melhor ainda, use 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"); } } 

String é imutável em java. você não pode modificar / alterar um literal / object de string existente.

String s = “Olá”; s = s + “hi”;

Aqui a referência anterior s é substituída pela nova referência apontando para o valor “HelloHi”.

No entanto, para trazer a mutabilidade, temos StringBuilder e StringBuffer.

StringBuilder s = novo StringBuilder (); s.append (“Hi”);

isso acrescenta o novo valor “Hi” às mesmas referências. //

Aaron Digulla tem a melhor resposta até agora. Uma variação de sua segunda opção é usar o invólucro ou class de contêiner MutableObject da versão 3+ da biblioteca commons lang:

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

você salva a declaração da class container. A desvantagem é uma dependência do commons lang lib. Mas o lib tem bastante function útil e quase todo projeto maior em que trabalhei o usou.

    Intereting Posts