Java에서 참조로 문자열을 전달하시겠습니까?
나는 에서 다음을 하는 것에 익숙하다.C
:
void main() {
String zText = "";
fillString(zText);
printf(zText);
}
void fillString(String zText) {
zText += "foo";
}
그리고 그 결과:
foo
그러나 자바에서는 이것이 효과가 없는 것 같다.내 생각에 왜냐하면String
참조에 의해 전달되는 대신 객체가 복사된다.스트링스는 항상 참고가 되는 물건이라고 생각했다.
이게 무슨 일이야?
세 가지 옵션:
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가 가장 좋은 옵션이다.
자바에서는 어떤 것도 참조로 전달되지 않는다.모든 것은 가치에 의해 전달된다.개체 참조는 값으로 전달된다.또한 문자열은 불변한다.전달된 스트링에 추가하면 새 스트링만 얻을 수 있다.반환 값을 사용하거나 StringBuffer를 대신 전달할 수 있다.
현재 일어나고 있는 일은 참조가 가치에 의해 전달된다는 것, 즉 참조의 복사본이 전달된다는 것이다.Java의 어떤 것도 참조로 전달되지 않으며, 문자열은 불변하므로, 해당 할당은 참조의 복사본이 가리키는 새로운 문자열 객체를 만든다.원래의 참조는 여전히 빈 문자열을 가리킨다.
이것은 어떤 물체에서도 마찬가지일 것이다. 즉, 방법의 새로운 값으로 설정한다.아래 예제는 단지 현재 일어나고 있는 일을 더 분명하게 만들 뿐이지만, 끈을 연결시키는 것은 정말로 같은 것이다.
void foo( object o )
{
o = new Object( ); // original reference still points to old value on the heap
}
자바.의끈은 불변이다.
나는 URL을 붙여넣는 것을 싫어하지만, 자바랜드에 있는 당신이 읽고 이해하기 위해서는 https://docs.oracle.com/javase/10/docs/api/java/lang/String.html이 필수적이다.
Java의 모든 인수는 값으로 전달된다.a를 통과할 때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 구성
객체는 참조로 전달되고, 원시성은 값으로 전달된다.
끈은 원시적인 것이 아니라 물체로서 특수한 물체의 경우다.
이것은 기억력 절약을 위한 것이다.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
==는 메모리 주소(참조)를 검사하고, .cs는 내용(값)을 검사하고 있다.
문자열은 자바에서 불변의 개체다.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");
}
또 다른 옵션은 다음과 같이 String을 스코프 변수로 하는 클래스를 만드는 것이다(강제화).
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";
}
대답은 간단하다자바에서는 문자열이 불변하다.따라서 '최종' 수식어(또는 C/C++의 'const')를 사용하는 것과 같다.그래서 일단 배정받으면 그렇게 바꿀 수 없다.
문자열이 가리키는 값을 변경할 수 있지만 이 문자열이 현재 가리키고 있는 실제 값은 변경할 수 없다.
즉String s1 = "hey"
만들 수 있다.s1 = "woah"
그랬다고 해서 그 문자열의 기본값을 바꿀 수는 없다, 이 경우: 문자의 기고 을 수 있다(이따라서는 일단 하여 배정받으면 될 수 있다이따라서 "이봐")."Hey"는 PlusEqals 등을 사용하여 할당되면 다른 무언가가 될 수 있다.s1 += " whatup != "hey whatup"
).
그렇게 하려면 StringBuilder 또는 StringBuffer 클래스 또는 기타 변경 가능한 컨테이너를 사용한 다음 .toString()을 호출하여 객체를 문자열로 다시 변환하십시오.
참고: 문자열은 종종 해시 키로 사용되기 때문에 문자열이 불변하는 이유 중 일부 입니다.
문자열은 자바에서 특별한 클래스다."String 인스턴스가 생성되면 String 인스턴스의 내용은 절대 변경되지 않음"을 의미하는 Thread Safe입니다.
여기 무슨 일이 일어나고 있는가.
zText += "foo";
먼저, Java 컴파일러는 zText String 인스턴스의 값을 얻은 다음 값이 "foo"를 추가하는 zText인 새 String 인스턴스를 만든다.따라서 zText가 가리키는 인스턴스가 변경되지 않는 이유를 알 수 있다.그것은 완전히 새로운 예다.사실, 심지어 String "foo"도 새로운 String 인스턴스다.따라서 이 문장의 경우 Java는 두 개의 String 인스턴스를 만들 것이다. 하나는 "foo"이고 다른 하나는 zText 추가 "foo"의 값이다.규칙은 간단하다:문자열 인스턴스의 값은 변경되지 않는다.
메서드 fillString의 경우 StringBuffer를 파라미터로 사용하거나 다음과 같이 변경할 수 있다.
String fillString(String zText) {
return zText += "foo";
}
자바에서는 문자열을 불변한다.
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");
}
}
문자열은 자바로 불변한다.기존 문자열 리터럴/개체인 수정/변경할 수 없음.
문자열 s="hello"; s=s+"hi";
여기서 이전의 참조 s는 "HelloHi" 값을 가리키는 새로운 참조 s로 대체된다.
그러나, 돌연변이를 가져오기 위해 StringBuilder와 StringBuffer가 있다.
StringBuilder s=new StringBuilder(); s.append("Hi");
이것은 새로운 값 "Hi"를 동일한 참조 s. //에 추가한다.
아론 디굴라가 지금까지 최고의 해답을 가지고 있다.그의 두 번째 옵션의 변화는 공용 언어 라이브러리 버전 3+의 래퍼 또는 컨테이너 클래스 MutableObject를 사용하는 것이다.
void fillString(MutableObject<String> c) { c.setValue(c.getValue() + "foo"); }
컨테이너 클래스의 선언을 저장하십시오.단점은 공용 언어 리브에 의존하는 것이다.하지만 lib는 꽤 많은 유용한 기능을 가지고 있고 내가 작업한 거의 모든 더 큰 프로젝트들이 그것을 사용했다.
Java에서 참조로 객체(String 포함)를 전달하기 위해 주변 어댑터의 멤버로 전달할 수 있다.제네릭을 사용하는 솔루션은 다음과 같다.
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());
}
}
더 궁금한 사람을 위해서.
class Testt {
static void Display(String s , String varname){
System.out.println(varname + " variable data = "+ s + " :: address hashmap = " + s.hashCode());
}
static void changeto(String s , String t){
System.out.println("entered function");
Display(s , "s");
s = t ;
Display(s,"s");
System.out.println("exiting function");
}
public static void main(String args[]){
String s = "hi" ;
Display(s,"s");
changeto(s,"bye");
Display(s,"s");
}
}
이제 위의 코드를 실행하면 주소 정보를 확인할 수 있다.
hashcodes
문자열 변수 s를 사용하여 변경. 함수에서 변수 s에 새 개체가 할당됨changeto
가
참조URL: https://stackoverflow.com/questions/1270760/passing-a-string-by-reference-in-java
'IT이야기' 카테고리의 다른 글
Vue: v-for의 입력 배열에서 입력 변경에 대응 (0) | 2022.04.22 |
---|---|
자바를 위한 최고의 모의 프레임워크는 무엇인가? (0) | 2022.04.22 |
Iterator를 스트림으로 변환하는 방법 (0) | 2022.04.22 |
Java가 서명되지 않은 int를 지원하지 않는 이유는? (0) | 2022.04.22 |
링크 Javascript에서 문자열 부분 바꾸기 (0) | 2022.04.22 |