[java] C #과 Java의 삼항 연산자 (? :)의 차이점

저는 C # 초보자이고 문제가 발생했습니다. 삼항 연산자 ( ? :)를 다룰 때 C #과 Java에는 차이가 있습니다 .

다음 코드 세그먼트에서 네 번째 줄이 작동하지 않는 이유는 무엇입니까? 컴파일러는 오류 메시지를 표시합니다 there is no implicit conversion between 'int' and 'string'. 다섯 번째 줄도 작동하지 않습니다. 둘 다 List객체 죠, 그렇죠?

int two = 2;
double six = 6.0;
Write(two > six ? two : six); //param: double
Write(two > six ? two : "6"); //param: not object
Write(two > six ? new List<int>() : new List<string>()); //param: not object

그러나 동일한 코드가 Java에서 작동합니다.

int two = 2;
double six = 6.0;
System.out.println(two > six ? two : six); //param: double
System.out.println(two > six ? two : "6"); //param: Object
System.out.println(two > six ? new ArrayList<Integer>()
                   : new ArrayList<String>()); //param: Object

C #에서 누락 된 언어 기능은 무엇입니까? 있는 경우 추가되지 않는 이유는 무엇입니까?



답변

관통 찾고 C 것은 # 5 언어 사양 섹션 7.14 : 조건부 연산자 우리는 다음을 볼 수 있습니다 :

  • x에 X 유형이 있고 y에 Y 유형이 있으면

    • 암시 적 변환 (§6.1)이 X에서 Y로 존재하지만 Y에서 X로가 아닌 경우 Y는 조건식의 유형입니다.

    • 암시 적 변환 (§6.1)이 Y에서 X로 존재하지만 X에서 Y로가 아닌 경우 X는 조건식의 유형입니다.

    • 그렇지 않으면 식 유형을 확인할 수 없으며 컴파일 타임 오류가 발생합니다.

즉, x와 y가 서로 변환 될 수 있는지 여부를 찾으려고 시도 하고 그렇지 않으면 컴파일 오류가 발생합니다. 우리의 경우 intstring는 컴파일되지 않도록 명시 적 또는 암시 적 변환이 없습니다.

이것을 Java 7 언어 사양 섹션 15.25 : 조건부 연산자 와 대조하십시오 .

  • 두 번째 및 세 번째 피연산자가 동일한 유형 (널 유형일 수 있음)을 갖는 경우 이것이 조건식의 유형입니다. ( 아니요 )
  • 두 번째 및 세 번째 피연산자 중 하나가 기본 유형 T이고 다른 유형이 T에 boxing 변환 (§5.1.7)을 적용한 결과 인 경우 조건식의 유형은 T입니다. ( NO )
  • 두 번째 및 세 번째 피연산자 중 하나가 널 유형이고 다른 유형이 참조 유형 인 경우 조건식의 유형은 해당 참조 유형입니다. ( 아니요 )
  • 그렇지 않고 두 번째 및 세 번째 피연산자에 숫자 유형으로 변환 할 수있는 유형 (§5.1.8)이있는 경우 다음과 같은 몇 가지 경우가 있습니다. ( NO )
  • 그렇지 않으면 두 번째 및 세 번째 피연산자는 각각 S1 및 S2 유형입니다. T1을 S1에 권투 변환을 적용한 결과 유형이고 T2를 S2에 권투 변환을 적용한 결과 유형이라고 가정합니다.
    조건식의 유형은 캡처 변환 (§5.1.10)을 lub (T1, T2) (§15.12.2.7)에 적용한 결과입니다. ( )

그리고 섹션 15.12.2.7살펴보십시오. 실제 인수를 기반으로 유형 인수 추론 우리는 호출에 사용되는 유형으로 사용할 공통 조상을 찾으려고 시도하는 것을 볼 수 있습니다 Object. Object 입니다 전화가 작동 할 수 있도록 허용 인수.


답변

주어진 대답은 좋습니다. 이 C # 규칙은보다 일반적인 디자인 지침의 결과라고 덧붙일 것입니다. 여러 선택 항목 중 하나에서 식의 유형을 추론하라는 요청을 받으면 C #은 그중 가장 고유 한 항목을 선택 합니다 . 즉, C #에 “Giraffe, Mammal, Animal”과 같은 선택 항목을 제공하면 상황에 따라 가장 일반적인 동물 (동물)을 선택하거나 가장 구체적인 기린을 선택할 수 있습니다. 그러나 실제로 주어진 선택 사항 중 하나를 선택해야합니다 . C #은 “내 선택은 고양이와 개 사이에 있으므로 동물이 최선의 선택이라고 추론 할 것입니다”라고 말하지 않습니다. 그것은 주어진 선택이 아니기 때문에 C #은 그것을 선택할 수 없습니다.

삼항 연산자의 경우 C #은 더 일반적인 유형의 int 및 string을 선택하려고하지만 더 일반적인 유형은 아닙니다. 개체와 같이 처음에 선택되지 않은 유형을 선택하는 대신 C #은 유형을 유추 할 수 없다고 결정합니다.

또한 이것이 C #의 또 다른 디자인 원칙과 일치한다는 점에 유의합니다. 문제가 발생하면 개발자에게 알려주십시오. 그 언어는 “나는 당신이 의미하는 바를 추측하고 내가 할 수만 있다면 뒤죽박죽 이겠지”라고 말하지 않습니다. 언어는 “당신이 여기에 헷갈리는 것을 썼다고 생각합니다. 그리고 그것에 대해 말씀 드리겠습니다.”

또한 C #은 변수 에서 할당 된 값으로 추론하는 것이 아니라 다른 방향으로 추론합니다 . C #은 “객체 변수에 할당하고 있으므로 표현식을 객체로 변환 할 수 있어야합니다. 따라서 확실히 할 것입니다”라고 말하지 않습니다. 오히려 C #은 “이 식에는 형식이 있어야하며 형식이 개체와 호환되는지 추론 할 수 있어야합니다.”라고 말합니다. 표현식에 유형이 없으므로 오류가 발생합니다.


답변

제네릭 부분에 관하여 :

two > six ? new List<int>() : new List<string>()

C #에서 컴파일러는 오른쪽 식 부분을 일반적인 형식 으로 변환 하려고 합니다. 이후 List<int>List<string>두 가지 구성 유형이 있습니다, 하나는 다른 변환 할 수 없습니다.

Java에서 컴파일러는 변환하는 대신 공통 상위 유형찾으려고 하므로 코드 컴파일에는 암시 적 와일드 카드 사용 및 유형 삭제가 포함됩니다 .

two > six ? new ArrayList<Integer>() : new ArrayList<String>()

컴파일 유형 ArrayList<?>(실제로 는 공통 일반 상위 유형이므로 사용 컨텍스트에 따라 ArrayList<? extends Serializable>또는 ArrayList<? extends Comparable<?>>일 수 있음 ) 및 원시 런타임 유형 ArrayList(공통 원시 상위 유형이므로)이 있습니다.

예를 들어 (직접 테스트) ,

void test( List<?> list ) {
    System.out.println("foo");
}

void test( ArrayList<Integer> list ) { // note: can't use List<Integer> here
                                 // since both test() methods would clash after the erasure
    System.out.println("bar");
}

void test() {
    test( true ? new ArrayList<Object>() : new ArrayList<Object>() ); // foo
    test( true ? new ArrayList<Integer>() : new ArrayList<Object>() ); // foo 
    test( true ? new ArrayList<Integer>() : new ArrayList<Integer>() ); // bar
} // compiler automagically binds the correct generic QED


답변

Java 및 C # (및 대부분의 다른 언어)에서 표현식의 결과에는 유형이 있습니다. 삼항 연산자의 경우 결과에 대해 평가되는 두 개의 가능한 하위 표현식이 있으며 둘 다 동일한 유형을 가져야합니다. Java의 경우 autoboxing int을 통해 변수를로 변환 할 수 있습니다 Integer. 이제 둘 다 Integer에서 String상속 받으 므로 Object간단한 축소 변환을 통해 동일한 유형으로 변환 할 수 있습니다.

반면에 C #에서 an int은 기본 형식이며 string또는 다른 object.


답변

이것은 매우 간단합니다. string과 int 사이에는 암시 적 변환이 없습니다. 삼항 연산자는 동일한 유형을 갖기 위해 마지막 두 피연산자가 필요합니다.

시험:

Write(two > six ? two.ToString() : "6");


답변