Java에서 String 유형의 매개 변수 전달 문제를 간단히 설명합니다.

요약: 본고는 실현 원리의 측면에서 자바 언어에서 String을 유형으로 하는 변수가 방법 매개 변수로 할 때 나타내는'비대상'의 특성을 논술하고 분석했다.
1. 처음 예
코드를 쓰는 데 가장 중요한 것은 실천이다. 반복적인 실험을 거치지 않고 나온 말은 그저 헛된 생각일 뿐이다.따라서 본고에서 먼저 간단한 예시로 핵심 화제를 제시한다.

public class StringAsParamOfMethodDemo { 
    public static void main(String[] args) { 
       StringAsParamOfMethodDemo StringAsParamOfMethodDemo = new StringAsParamOfMethodDemo(); 
       StringAsParamOfMethodDemo.testA(); 
    } 
    private void testA() { 
       String originalStr = "original"; 
       System.out.println("Test A Begin:"); 
       System.out.println("The outer String: " + originalStr); 
       simpleChangeString(originalStr); 
       System.out.println("The outer String after inner change: " + originalStr); 
       System.out.println("Test A End."); 
       System.out.println(); 
    } 
    public void simpleChangeString(String original) { 
       original = original + " is changed!"; 
       System.out.println("The changed inner String: " + original); 
    } 
} 
이 코드의 논리는 다음과 같다. 먼저 String 형식의 국부 변수를 부여한 다음에 이 변수를 매개 변수로 한 방법에 보내고 이 방법에서 이 변수의 값을 바꾼다.컴파일이 실행된 후에 출력 결과는 다음과 같습니다.

Test A Begin:
The outer String: original
The changed inner String: original is changed!
The outer String after inner change: original
Test A End.
이 결과는 방법 내부에서 String 유형의 변수에 대한 재부여 작업이 이 변수의 원형에 아무런 영향을 미치지 않았다는 것을 나타낸다.자, 이 예시의 논리와 운행 결과는 모두 명확하게 보여 줍니다. 다음에 이 작은 프로그램에 대해 분석을 하겠습니다.그 전에 자바에서 소위'전치'와'전인용'문제를 살펴보자.
2. Java의 전송 값 및 전송 참조 문제
많은 자바를 처음 배운 프로그래머들이 이 문제에 대해 깊이 생각하고 있다. 그것은 이른바'C언어의 전가와 바늘 문제'가 자바 언어에서 같은 유형의 표현이기 때문이다.
마지막으로 얻은 결론은 다음과 같다.
Java에서 기본 유형이 매개 변수로 전송될 때 이 매개 변수가 방법 내에서 어떻게 바뀌든지 간에 외부의 변수 원형은 항상 변하지 않는다. 코드는 위의 예와 유사하다.

int number = 0; 

changeNumber(number) {number++}; // int  

System.out.println(number);//이때number는 여전히 0입니다
이것을'값 전달'이라고 한다. 즉, 방법은 매개 변수(즉 원형 변수의 한 값의 복사)를 조작하는 것이다. 변경된 것은 원형 변수의 한 복사일 뿐이지 변수 자체가 아니다.그래서 변수의 원형은 따라서 바뀌지 않는다.
그러나 방법이 전송된 매개 변수가 비기본 유형일 때(즉 대상 유형의 변수라는 뜻) 방법은 매개 변수를 바꾸는 동시에 변수의 원형도 바뀐다. 코드는 상기 예시와 유사하다.

StringBuffer strBuf = new StringBuffer(“original”); 

changeStringBuffer(strBuf) {strbuf.apend(“ is changed!”)} // StringBuffer  

System.out.println(strBuf);//이때 strBuf의 값은 original is changed로 바뀝니다!   
이러한 특성은'인용 전달'이라고 하고 주소라고도 한다. 즉, 방법은 매개 변수 변수를 조작할 때 변수의 인용을 복사한 다음에 인용을 통해 변수(여기는 대상)의 진정한 주소를 찾아 조작한다.이 방법이 끝난 후, 방법 내부의 그 매개 변수는 따라서 사라진다.그러나 이 변수는 대상의 인용일 뿐이고 대상이 있는 실제 주소를 가리키기 때문에 그 사라짐은 부정적인 영향을 미치지 않는다는 것을 알아야 한다.돌이켜 보면 원형 변수는 본질적으로 그 대상의 인용이기도 하고 파라미터 변수와 똑같다. 당초 파라미터 변수가 가리키는 대상에 대한 변화는 근본적으로 원형 변수가 가리키는 대상에 대한 변화였다.그래서 원형 변수가 대표하는 대상은 이렇게 바뀌었고 이런 변화는 보존되었다.
이 고전적인 문제를 이해하면 많은 세심한 독자들이 즉각 새로운 의문을 제기할 것이다. "그런데 String 유형은 자바 언어에서 비기본적인 유형에 속한다. 그 방법의 변화는 왜 저장되지 않았을까!"확실히 이것은 문제이며, 이 새로운 의문은 그 고전적인 문제의 전체 결론을 거의 뒤집었다.정말 그렇습니까?자, 이제 우리 계속 분석합시다.
3. String 매개 변수 전달 문제에 대한 곡해 중 하나인 직접 값과 대상 값
String 형식의 변수를 매개 변수로 할 때 어떻게 기본 형식의 변수처럼 전치 방식으로 전달할 수 있습니까?이 문제에 대해 어떤 친구들은 해명을 했지만 안타깝게도 정확하지 않았다.
한 가지 해석은 String 유형의 변수에 값을 부여할 때 new가 대상을 내지 않고 문자열로 값을 부여하기 때문에 자바는 이 String 유형의 변수를 기본 형식으로 간주했다.즉, String str = new String ("original");,Stringstr = "original"대신이것이 문제입니까?우리는 이전의 예시를 약간 개조해서 운행한 후에 결과를 보면 알 수 있다.개조된 코드는 다음과 같습니다.

private void testB() { 
   String originalStr = new String("original"); 
   System.out.println("Test B Begin:"); 
   System.out.println("The outer String: " + originalStr); 
   changeNewString(originalStr); 
   System.out.println("The outer String after inner change: " + originalStr); 
   System.out.println("Test B End:"); 
   System.out.println(); 
   } 
public void changeNewString(String original) { 
   original = new String(original + " is changed!"); 
   System.out.println("The changed inner String: " + original); 
   } 
이번 운행 결과가 어떤지 봅시다.

Test B Begin:
The outer String: original
The changed inner String: original is changed!
The outer String after inner change: original
Test B End.
실천은 이런 견해가 틀렸다는 것을 증명한다.
실제로 문자열의 직접 값과 new로 나온 대상 값의 차이는 저장 방식이 다르다는 데 있다.
간단한 설명:
문자열이 직접 값을 지정할 때 String 유형의 변수가 참조하는 값은 클래스의 상수 풀에 저장됩니다.original 자체는 문자열 상수이고, 다른 한편, String은 변하지 않는 유형이기 때문에 이 String 유형의 변수는 하나의 상수에 대한 인용과 같다.이런 상황에서 변수의 메모리 공간 크기는 컴파일 기간에 이미 확정된 것이다.
new 대상의 방식은 original을 String 대상의 메모리 공간에 저장하는 것입니다. 이 저장 동작은 운행 기간에 진행됩니다.이런 상황에서 자바는 original이라는 문자열을 상수로 취급하는 것이 아니다. 왜냐하면 이것은 String 대상을 만드는 매개 변수로 나타나기 때문이다.
따라서 String의 값 부여 방식과 그 매개 변수의 값 전달 문제는 직접적인 관계가 없다.한마디로 이런 해석은 정해가 아니다.
넷째, String 매개 변수 전달 문제에 대한 곡해의 두 번째 - "="변수와 방법 변수
또 어떤 친구들은 변수가 동기화되지 않는 문제는 값을 바꾸는 방식에 있다고 생각한다.
이런 견해는'Java에서 매개 변수의 값을 바꾸는 데는 두 가지 상황이 있는데 첫 번째는'='를 사용하여 직접 값을 부여하여 바꾸는 것이다.둘째, 일부 대상에 대한 인용은 일정한 경로를 통해 구성원 데이터, 예를 들어 대상을 통과하는 방법 등을 변경한다.첫 번째 상황에 대해 그 변화는 이 매개 변수에 전송된 방법 이외의 데이터나 원본 데이터에 영향을 주지 않는다.두 번째 방법은 반대로 원본 데이터에 영향을 미친다. 인용 지시의 대상이 변하지 않았기 때문에 구성원의 데이터를 바꾸는 것은 실질적으로 이 대상이다.
이런 방식은 듣기에 약간 그런 것 같다. 우리는 여전히 낡은 방법으로 데모를 작성하고 작은 실험을 한다. 코드는 다음과 같다.

    private void testC() { 
       String originalStr = new String("original"); 
       System.out.println("Test C Begin:"); 
       System.out.println("The outer String: " + originalStr); 
       changeStrWithMethod(originalStr); 
       System.out.println("The outer String after inner change: " + originalStr); 
       System.out.println("Test C End."); 
       System.out.println(); 
} 
    private static void changeStrWithMethod(String original) { 
       original = original.concat(" is changed!"); 
       System.out.println("The changed inner String: " + original); 
}
결과는 다음과 같습니다.

Test C Begin:
The outer String: original
The changed inner String: original is changed!
The outer String after inner change: original
Test C End.
어때, 이것은 문제가 여기에서 나온 것이 아니라는 것을 증명하고, 또 하나의 해석은 실천 논거에서 요절했다.
그렇다면 도대체 어떤 원인이 이런 상황을 초래한 것일까?
자, 애쓰지 않겠습니다. 다음은 제 설명을 하겠습니다.
5. String 매개 변수 전달 문제의 문제점
사실 하나의 클래스나 API 프레임워크를 진정으로 이해하려면 가장 직접적인 방법은 원본 코드를 보는 것이다.
다음은 new에서 나온 String 대상의 작은 코드 (String 클래스 중), 즉 String 클래스의 구조 함수를 살펴보겠습니다.

  public String(String original) { 
        int size = original.count; 
        char[] originalValue = original.value; 
        char[] v; 
        if (originalValue.length > size) { 
          // The array representing the String is bigger than the new 
          // String itself.  Perhaps this constructor is being called 
          // in order to trim the baggage, so make a copy of the array. 
          int off = original.offset; 
              v = Arrays.copyOfRange(originalValue, off, off+size); 
        } else { 
          // The array representing the String is the same 
          // size as the String, so no point in making a copy. 
          v = originalValue; 
        } 
        this.offset = 0; 
        this.count = size; 
        this.value = v; 
}
아마도 당신은 안에 있는char[]를 알아차렸을 것입니다. 이것은 String의 저장이 실제로char[]를 통해 이루어졌다는 것을 설명합니다.어때요?사실은 창호지예요.자바 API에 정의된 기본 유형의 패키지 클래스를 기억하고 계신지 모르겠습니다.예를 들어 Integer는 int 포장류, Float는 float 포장류 등이다.이러한 포장류에 대한 값 조작은 사실상 그에 대응하는 기본 유형의 조작을 통해 이루어진 것이다.뭔가 깨달았죠?네, String은char[]의 포장류에 해당합니다.포장류의 특질 중 하나는 그 값을 조작할 때 그에 대응하는 기본 유형의 성질을 나타낸다는 것이다.파라미터가 전달될 때 포장류는 이렇게 나타난다.그래서 스트링이 이런 상황에서 보여준 결과에 대한 해석은 자연스레 나온다.마찬가지로 Integer, Float 등 이런 포장류와 String은 이런 상황에서 똑같은 모습을 보였고 구체적인 분석은 여기서 생략하고 관심 있는 친구는 스스로 실험을 할 수 있다.
이것이 바로 문자열에 대한 조작이 서로 다른 방법을 통해 이루어질 때 StringBuffer를 사용하는 것을 추천하는 진정한 이유이다.String Buffer가 왜 String이라는 현상을 나타내지 않는지 여러분이 다시 한 번 보시면 String Buffer의 실현을 알게 될 것입니다. 여기서 더 이상 언급하지 않겠습니다.
여섯, 마지막
이로써 String 유형의 매개 변수 전달 문제의 원리도 드러났다.사실 분석 방식이 정확하기만 하면 사고는 결국 정확한 결론을 얻는다는 것을 알 수 있다.
정확한 분석 방법의 기초는 다음과 같다.
1. 실천을 많이 하라: 손은 절대 게으름을 피우지 마라. 실천은 반드시 진정한 지식을 얻는다.
2. 원리를 바탕으로 한다. 프로그램 논리를 명확하게 하는 가장 직접적이고 간단한 방법은 원본 코드를 보는 것이다. 이것은 의심할 여지가 없다.
이 두 가지 기초를 바탕으로 분석하면 적은 노력으로 큰 효과를 거둘 수 있는 경우가 많다.이것은 경험담이자 분석 절차의'지름길'방식 중의 하나라고 할 수 있다.

좋은 웹페이지 즐겨찾기