«Неправильный» тип возвращаемого значения при использовании оператора if против троичного оператора в Java

java if-statement return ternary-operator

503 просмотра

2 ответа

12015 Репутация автора

В следующем классе возвращаемый тип двух методов не согласуется с идеей, что троичный оператор:

return condition?a:b;

эквивалентно

if(condition) {
    return a;
} else{ 
    return b;
}

Первый возвращает Double, а второй Long:

public class IfTest {
    public static Long longValue = 1l;
    public static Double doubleValue = null;

    public static void main(String[] args) {
        System.out.println(getWithIf().getClass());// outpus Long
        System.out.println(getWithQuestionMark().getClass());// outputs Double
    }

    public static Object getWithQuestionMark() {
        return doubleValue == null ? longValue : doubleValue;
    }

    public static Object getWithIf() {
        if (doubleValue == null) {
            return longValue;
         } else {
            return doubleValue;
        }
    }
}

Я могу представить, что это связано с узким приведением компилятором возвращаемого типа, getWithQuestionMark()но подходит ли этот язык? Это, конечно, не то, что я ожидал.

Любые идеи приветствуются!

Редактировать: есть очень хорошие ответы ниже. Кроме того, следующий вопрос, на который ссылается @sakthisundar, исследует еще один побочный эффект продвижения типов, происходящий в троичном операторе: сложный троичный оператор в Java - автобокс

Автор: Miquel Источник Размещён: 24.08.2012 11:57

Ответы (2)


14 плюса

1143571 Репутация автора

Решение

В основном это соответствует правилам раздела 15.25 JLS , а именно:

В противном случае, если второй и третий операнды имеют типы, которые можно преобразовать (§5.1.8) в числовые типы, то существует несколько случаев:

  • [...]

  • В противном случае двоичное числовое продвижение (§5.6.2) применяется к типам операндов, а тип условного выражения является продвинутым типом второго и третьего операндов.

Поэтому раздел 5.6.2 следует, что будет в основном включает распаковку - так что это делает вашу работу выражения , как будто longValueи doubleValueбыли типов longи doubleсоответственно, и увеличивающееся продвижение применяется к , longчтобы получить общий тип результата double.

Это doubleтогда помещено в коробку, чтобы возвратить Objectметод.

Автор: Jon Skeet Размещён: 24.08.2012 12:03

3 плюса

28950 Репутация автора

В дополнение к ответу @ Jon, глядя на байт-код, который вы видите:

public static java.lang.Object getWithQuestionMark();
  Code:
   0:   getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   3:   ifnonnull       16
   6:   getstatic       #8; //Field longValue:Ljava/lang/Long;
   9:   invokevirtual   #9; //Method java/lang/Long.longValue:()J
   12:  l2d
   13:  goto    22
   16:  getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   19:  invokevirtual   #10; //Method java/lang/Double.doubleValue:()D
   22:  invokestatic    #11; //Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
   25:  astore_0
   26:  aload_0
   27:  areturn

Принимая во внимание, что если вы скажете компилятору, что вас не интересуют цифры:

public static Object getWithQuestionMark() {
    return doubleValue == null ? (Object)longValue : (Object)doubleValue;
}

вы получите то, что вы были после (байт-код)

public static java.lang.Object getWithQuestionMark();
  Code:
   0:   getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   3:   ifnonnull       12
   6:   getstatic       #8; //Field longValue:Ljava/lang/Long;
   9:   goto    15
   12:  getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   15:  areturn

выходы:

$ java IfTest
class java.lang.Long
class java.lang.Long
Автор: beny23 Размещён: 24.08.2012 12:10
Вопросы из категории :
32x32