어레이[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; } }
evaluated
evaluated evaluated
이 문제는 문자열 연결 및 할당 연산자로 한정되어 있는 것 같습니다.
+=
왼쪽 피연산자로 부작용이 있는 식을 사용합니다(예:array[test()]+="a"
,array[ix++]+="a"
,test()[index]+="a"
, 또는test().field+="a"
. 문자열 연결을 활성화하려면 적어도 하나의 변에 유형이 있어야 합니다.String
. 다른 유형 또는 구조에서 이를 재현하려고 하면 실패했습니다.
이것은 에 있는 버그입니다.javac
JDK-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
'IT이야기' 카테고리의 다른 글
매크로에서 의미 없는 do-while 및 if-else 문을 사용하는 이유는 무엇입니까? (0) | 2022.07.05 |
---|---|
RxJava에서는 언제 맵과 플랫맵을 사용합니까? (0) | 2022.07.05 |
옵션에서의 사용 (0) | 2022.07.05 |
Java: 열거에 지정된 문자열이 포함되어 있는지 확인하시겠습니까? (0) | 2022.07.04 |
v-bind를 사용하여 Vue가 거짓 특성을 표시하도록 강제하려면 어떻게 합니까? (0) | 2022.07.04 |