TargetTypingDRAFT
A numerical expression (e.g., 1/3
) can have a different type depending on which context it is placed in (e.g., in int x = 1/3
the type of 1/3
is int
, but in double x = 1/3
the type of 1/3
is double
).
The type of a numerical expression depends on the type expected by the surrounding context
The type of a numerical expression is determined by the expression
CorrectionHere is what's right.
An expression like 1/3
always has type int
.
The type of an expression is determined by only looking at that expression, without looking at the context in which the expression is located (there are some exceptions to this rule, see below).
A given numeric expression has a single, statically determined type,
no matter what context it is located in
(e.g., whether it is the e
in int x = e
or in double x = e
).
The type can be determined by statically analyzing the expression bottom up:
the type of the subexpressions and the signatures of the operators or methods used.
E.g., 1/3
has type int
, because 1
is a literal of type int
,
3
is a literal of type int
, and the /
operator, given two int
values,
produces an int
result, and thus the entire expression evaluates to an int
(i.e., the type of the expression is int
).
Exceptions
However, an expression involving generics (type parameters) has a parameterized type, and to infer a specific type the Java compiler may look at the context (see, e.g., Type Inference in the Java tutorial):
class Collections {
public static <T> List<T> emptyList() { ... };
}
List<String> strings = Collections.emptyList();
List<Pacman> pacmans = Collections.emptyList();
Here the generic type of expression Collections.emptyList()
is List<T>
, where T
can be anything. The compiler here does infer the specific type from the context in which the expression is located (more specifically, from the target by which the expression’s value will be used): the inferred type of the first occurrence of this expression is List<String>
, the inferred type of the second occurrence is List<Pacman>
. Note that this inference only happens for generic types, and only the type parameter (here, T
) is inferred.
Moreover, Java 8 introduces more target typing (motivated through its use of lambda expressions and the different functional interfaces they may be typed as).
public interface Callable<V> {
V call() throws Exception;
}
public interface PrivilegedAction<T> {
T run();
}
Callable<String> c = () -> "done";
PrivilegedAction<String> a = () -> "done";
Here the first occurrence of the lambda expression ()->"done"
has type Callable<String>
, but the second occurrence of the exact same expression has type PrivilegedAction<String>
.
However, note that even with all the target typing Java supports, 1/3
still is of type int
, always.