IT이야기

어레이[idx+]+="a"가 Java 8에서 한 번 idx가 증가하지만 Java 9와 10에서는 두 번 증가하는 이유는 무엇입니까?

cyworld 2022. 7. 5. 22:20
반응형

어레이[idx+]+="a"가 Java 8에서 한 번 idx가 증가하지만 Java 9와 10에서는 두 번 증가하는 이유는 무엇입니까?

도전을 위해 동료 코드 골퍼는 다음과 같은 코드를 작성했습니다.

import java.util.*;
public class Main {
  public static void main(String[] args) {
    int size = 3;
    String[] array = new String[size];
    Arrays.fill(array, "");
    for (int i = 0; i <= 100;) {
      array[i++ % size] += i + " ";
    }
    for (String element: array) {
      System.out.println(element);
    }
  }
}

Java 8에서 이 코드를 실행하면 다음과 같은 결과가 나타납니다.

1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 46 49 52 55 58 61 64 67 70 73 76 79 82 85 88 91 94 97 100 
2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 59 62 65 68 71 74 77 80 83 86 89 92 95 98 101 
3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 

Java 10에서 이 코드를 실행하면 다음과 같은 결과가 나타납니다.

2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 

Java 10을 사용하면 번호부여는 완전히 해제됩니다.그래서 여기서 무슨 일이 일어나고 있는 거야?Java 10의 버그입니까?

코멘트에서 후속 조치:

  • 이 문제는 Java 9 이후에 컴파일 했을 때 발생합니다(Java 10에서 발견되었습니다).Java 8에서 이 코드를 컴파일한 후 Java 9 또는 Java 11 얼리 액세스를 포함한 이후 버전에서 실행하면 예상된 결과를 얻을 수 있습니다.

  • 이러한 종류의 코드는 비표준이지만 사양에 따라 유효합니다.Kevin Cruizssen골프 챌린지 토론에서 발견한 이상한 사용 사례입니다.

  • Didier L은 훨씬 작고 이해하기 쉬운 코드를 사용하여 문제를 단순화했습니다.

      class Main {
        public static void main(String[] args) {
          String[] array = { "" };
          array[test()] += "a";
        }
        static int test() {
          System.out.println("evaluated");
          return 0;
        }
      }
    

    Java 8에서 컴파일했을 때의 결과:

      evaluated
    

    Java 9 및 10에서 컴파일된 결과:

      evaluated
      evaluated
    
  • 이 문제는 문자열 연결 및 할당 연산자로 한정되어 있는 것 같습니다.+=왼쪽 피연산자로 부작용이 있는 식을 사용합니다(예:array[test()]+="a",array[ix++]+="a",test()[index]+="a", 또는test().field+="a". 문자열 연결을 활성화하려면 적어도 하나의 변에 유형이 있어야 합니다.String. 다른 유형 또는 구조에서 이를 재현하려고 하면 실패했습니다.

이것은 에 있는 버그입니다.javacJDK-8204322의 버그 ID로 팀이 확인한 바와 같이 JDK9(스트링 연결과 관련하여 일부 변경을 가한 것으로 추정됩니다)부터라고 생각됩니다.회선의 대응하는 바이트 코드를 보면, 다음과 같습니다.

array[i++%size] += i + " ";

그 이유는 다음과 같습니다.

  21: aload_2
  22: iload_3
  23: iinc          3, 1
  26: iload_1
  27: irem
  28: aload_2
  29: iload_3
  30: iinc          3, 1
  33: iload_1
  34: irem
  35: aaload
  36: iload_3
  37: invokedynamic #5,  0 // makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;
  42: aastore

마지막 장소aaload는 어레이로부터의 실제 부하입니다.다만, 그 부분은

  21: aload_2             // load the array reference
  22: iload_3             // load 'i'
  23: iinc          3, 1  // increment 'i' (doesn't affect the loaded value)
  26: iload_1             // load 'size'
  27: irem                // compute the remainder

그 표현과 대략 일치합니다array[i++%size](실제 로딩과 스토어 포함)이 2회 들어 있습니다.이는 jls-15.26.2에 기재되어 있듯이 올바르지 않습니다.

양식의 복합 할당 표현식E1 op= E2와 동등하다E1 = (T) ((E1) op (E2)),어디에T의 유형입니다.E1단, 1회만 평가됩니다.

그래서 그 표현은array[i++%size] += i + " ";, 부품array[i++%size]한 번만 평가해야 합니다.단, 2회 평가됩니다(부하용으로 1회, 스토어용으로 1회).

네, 이건 버그입니다.


일부 업데이트:

버그는 JDK 11에서 수정되어 JDK 10(여기 및 여기)으로 백포트되었지만 퍼블릭업데이트를 수신하지 않기 때문에 JDK 9로 백포트되지 않았습니다.

Aleksey Shipilev는 JBS 페이지에서 다음과 같이 언급하고 있습니다(또, 코멘트에서는 @DidierL).

: " " " "-XDstringConcat=inline

that that것 that that that that that that that 。StringBuilder그는없없 없없없다다

언급URL : https://stackoverflow.com/questions/50683786/why-does-arrayidx-a-increase-idx-once-in-java-8-but-twice-in-java-9-and-1

반응형