[java] String 클래스는 + 연산자를 어떻게 재정의합니까?

Java에서 String이 클래스 일 때 + 연산자를 사용하여 String을 추가 할 수있는 이유는 무엇입니까? 에서 String.java코드 나는이 연산자에 대한 구현을 찾을 수 없습니다. 이 개념이 객체 방향을 위반합니까?



답변

자바에서 다음과 같은 간단한 표현을 봅시다

int x=15;
String temp="x = "+x;

컴파일러는 내부적 "x = "+x;으로 변환 하고 정수를 문자열에 “추가”하는 StringBuilder데 사용 .append(int)합니다.

5.1.11. 문자열 변환

문자열 변환을 통해 모든 형식을 문자열 형식으로 변환 할 수 있습니다.

프리미티브 유형 T의 값 x는 먼저 적절한 클래스 인스턴스 작성 표현식 (§15.9)에 인수로 제공하여 참조 값으로 변환됩니다.

  • T가 부울 인 경우 new Boolean (x)을 사용하십시오.
  • T가 char이면 new Character (x)를 사용하십시오.
  • T가 byte, short 또는 int이면 new Integer (x)를 사용하십시오.
  • T가 길면 new Long (x)를 사용하십시오.
  • T가 float이면 new Float (x)를 사용하십시오.
  • T가 double이면 new Double (x)를 사용하십시오.

그런 다음이 참조 값은 문자열 변환에 의해 문자열 유형으로 변환됩니다.

이제 참조 값만 고려하면됩니다.

  • 참조가 널이면 문자열 “null”(4 개의 ASCII 문자 n, u, l, l)로 변환됩니다.
  • 그렇지 않으면, 인수없이 참조 된 객체의 toString 메소드를 호출하는 것처럼 변환이 수행됩니다. 그러나 toString 메소드를 호출 한 결과가 널이면 문자열 “null”이 대신 사용됩니다.

toString 메소드는 기본 클래스 Object (§4.3.2)에 의해 정의됩니다. Boolean, Character, Integer, Long, Float, Double 및 String과 같은 많은 클래스가이를 재정의합니다.

문자열 변환 컨텍스트에 대한 자세한 내용은 §5.4를 참조하십시오.

15.18.1.

문자열 연결 최적화 :
구현은 중간 문자열 개체를 생성 한 다음 폐기하지 않기 위해 한 단계로 변환 및 연결을 수행하도록 선택할 수 있습니다. 반복 문자열 연결 성능을 향상시키기 위해 Java 컴파일러는 StringBuffer 클래스 또는 유사한 기술을 사용하여 표현식 평가에 의해 생성 된 중간 문자열 객체의 수를 줄일 수 있습니다.

프리미티브 유형의 경우 구현시 기본 유형에서 문자열로 직접 변환하여 랩퍼 오브젝트 작성을 최적화 할 수도 있습니다.

최적화 된 버전은 실제로 전체 랩핑 된 문자열 변환을 먼저 수행하지 않습니다.

다음은 컴파일러가 백그라운드에서 StringBuilder로 변경되는 것을 볼 수있는 프리미티브를 변환하지 않아도 컴파일러가 사용하는 최적화 된 버전을 잘 보여줍니다.

http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/


이 자바 코드 :

public static void main(String[] args) {
    String cip = "cip";
    String ciop = "ciop";
    String plus = cip + ciop;
    String build = new StringBuilder(cip).append(ciop).toString();
}

이것을 생성합니다-두 연결 스타일이 어떻게 같은 바이트 코드로 이어지는 지보십시오.

 L0
    LINENUMBER 23 L0
    LDC "cip"
    ASTORE 1
   L1
    LINENUMBER 24 L1
    LDC "ciop"
    ASTORE 2

   // cip + ciop

   L2
    LINENUMBER 25 L2

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 3

    // new StringBuilder(cip).append(ciop).toString()

   L3
    LINENUMBER 26 L3

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 4
   L4
    LINENUMBER 27 L4
    RETURN

위의 예제와 주어진 예제의 소스 코드를 기반으로 한 바이트 코드가 생성되는 방식을 살펴보면 컴파일러가 내부적으로 다음 명령문을 변환했음을 알 수 있습니다.

cip+ciop; 

으로

new StringBuilder(cip).append(ciop).toString();

다시 말해서, +문자열 연결 의 연산자 는 더 자세한 StringBuilder관용구 의 약칭입니다 .


답변

+연산자 의 피연산자를 확인하는 Java 컴파일러 기능입니다 . 그리고 피연산자를 기반으로 바이트 코드를 생성합니다.

  • String의 경우 문자열을 연결하는 코드를 생성합니다.
  • 숫자의 경우 숫자를 추가하는 코드를 생성합니다.

이것은 Java 스펙이 말하는 것입니다 .

연산자 +를 -추가 연산자라고합니다. AdditiveExpression : MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression-MultiplicativeExpression

덧셈 연산자는 우선 순위가 동일하며 구문 적으로 왼쪽 연관되어 있습니다 (왼쪽에서 오른쪽으로 그룹화). (A)의 피연산자를 입력 할 경우 +작업자는 String다음 동작은 문자열 연결된다.

그렇지 않으면 연산자의 각 피연산자 +유형이 기본 숫자 유형으로 변환 가능한 (§5.1.8) 유형이어야합니다. 그렇지 않으면 컴파일 타임 오류가 발생합니다.

모든 경우에 이진 -연산자 의 각 피연산자 유형은 기본 숫자 유형으로 변환 가능한 유형 (§5.1.8)이어야합니다. 그렇지 않으면 컴파일 타임 오류가 발생합니다.


답변

String 클래스가 + 연산자를 어떻게 재정의합니까?

그렇지 않습니다. 컴파일러가 수행합니다. 엄밀히 말하면 컴파일러 는 String 피연산자에 + 연산자를 오버로드 합니다.


답변

우선 (+)가 오버로드되지 않은 오버로드

Java 언어는 Java 문자열 오브젝트에 과부하 된 문자열 연결 연산자 (+)에 대한 특별한 지원을 제공합니다.

  1. 왼쪽 피연산자가 문자열이면 연결로 작동합니다.

  2. 왼쪽 피연산자가 정수이면 덧셈 연산자로 작동합니다


답변

Java 언어는 문자열 연결 연산자 (+) 및 다른 객체를 문자열로 변환하는 데 특별한 지원을 제공합니다. 문자열 연결은 클래스 StringBuilder또는 메소드를 통해 구현됩니다 .StringBufferappend


답변

+적용될 때 연산자 의 의미는 String모든 사람들이 이미 작성한 것처럼 언어에 의해 정의됩니다. 충분히 설득력이없는 것으로 보이므로 다음 사항을 고려하십시오.

Int, float 및 double은 모두 서로 다른 이진 표현을 가지므로 두 개의 int를 추가하는 것은 비트 조작 측면에서 두 개의 float를 추가하는 것과 다른 작업입니다. 플로트의 경우 가수와 지수를 별도로 처리해야합니다.

따라서 원칙적으로 “추가”는 “추가 된”개체의 특성에 따라 다릅니다. Java는 문자열과 int 및 float (long, double, …)에 대해 그것을 정의합니다.


답변

+운영자는 일반적으로 대체됩니다 StringBuilder컴파일시. 해당 문제에 대한 자세한 내용은 이 답변 을 확인하십시오 .