プログラミング言語Javaにおける条件演算子(conditional operator) ?: と、子クラスから親クラスへの型推論(の一部)に関してメモ。

条件演算子の第2, 3項目に親クラスParentから派生した子クラスChild1, Child2を指定した場合、Javaでは部分式 (b ? c1 : c2) の静的型は共通の親クラスParentへと型推論される*1

class Parent {}
class Child1 extends Parent {}
class Child2 extends Parent {}

// 恒等関数id(ジェネリックメソッド)
static <T> T id(T x) { return x; }

boolean b = /*...*/;
Child1 c1 = new Child1();
Child2 c2 = new Child2();
Parent r = id(b ? c1 : c2);  // ★OK: T=Parentに型推論される

Java Language Specification, Java SE 8 Editionより一部引用。

There are three kinds of conditional expressions, classified according to the second and third operand expressions: boolean conditional expressions, numeric conditional expressions, and reference conditional expressions. The classification rules are as follows:

  • If both the second and the third operand expressions are boolean expressions, the conditional expression is a boolean conditional expression. (snip)
  • If both the second and the third operand expressions are numeric expressions, the conditional expression is a numeric conditional expression. (snip)
  • Otherwise, the conditional expression is a reference conditional expression.

The process for determining the type of a conditional expression depends on the kind of conditional expression, as outlined in the following sections.

Chapter 15. Expressions, 15.25. Conditional Operator ?

A reference conditional expression is a poly expression if it appears in an assignment context or an invocation context (§5.2. §5.3). Otherwise, it is a standalone expression.
The type of a standalone reference conditional expression is determined as follows:

  • (snip)
  • Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2).
Chapter 15. Expressions, 15.25.3. Reference Conditional Expressions

メモ: Child1, Child2に対するboxing conversionは恒等変換のため*2、T1=S1=Child1, T2=S2=Child2となる。lub(Child1, Child2) はLeast Upper Bound型推論過程(§4.10.4)によりParentとなる。同型に対するcapture conversionも恒等変換のため*3、最終的にはParentへと型推論される。

  • U1 = Child1, U2 = Child2
  • ST(U1) = EST(U1) = { Object, Parent, Child1 }
  • ST(U2) = EST(U2) = { Object, Parent, Child2 }
  • EC = { Object, Parent }
  • MEC = { Parent }, G = {}
  • lub(U1, U2) = Parent


*1:本文中では意図的に id<T> ジェネリックメソッドを経由させている。ここを Parent r = b ? c1 : c2; と記述した場合、条件演算子による部分式はpoly expressionとなり、本文にある型推論過程ではなく代入先の型 Parentへの単純な型推論が行われる。

*2:JLS 8, §5.1.7: "If p is a value of any other type, boxing conversion is equivalent to an identity conversion."

*3:JLS 8, §5.1.10: "Capture conversion on any type other than a parameterized type acts as an identity conversion."