I have seen it discussed somewhere that the following code results in obj being a Double, but that it prints 200.0 from the left hand side.
Object obj = true ? new Integer(200) : new Double(0.0);
System.out.println(obj);
Result: 200.0
However, if you put a different object in the right hand side, e.g. BigDecimal, the type of obj is Integer as it should be.
Object obj = true ? new Integer(200) : new BigDecimal(0.0);
System.out.println(obj);
Result: 200
I presume that the reason for this is something to do with casting the left hand side to a double in the same way that it happens for integer/double comparisons and calculations, but here the left and right sides do not interact in this way.
Why does this happen?
You need to read section 15.25 of the Java Language Specification.
In particular:
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
If one of the operands is of type byte or Byte and the other is of type short or Short, then the type of the conditional expression is short.
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression of type int whose value is representable in type T, then > - the type of the conditional expression is T.
If one of the operands is of type Byte and the other operand is a constant expression of type int whose value is representable in type byte, then the type of the conditional expression is byte.
If one of the operands is of type Short and the other operand is a constant expression of type int whose value is representable in type short, then the type of the conditional expression is short.
If one of the operands is of type; Character and the other operand is a constant expression of type int whose value is representable in type char, then the type of the conditional expression is char.
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion (§5.1.8) and value set conversion (§5.1.13).
So binary numeric promotion is applied, which starts with:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double, the other is converted to double.
That's exactly what happens here - the parameter types are converted to int and double respectively, the second operand (the third in the original expression) is then of type double, so the overall result type is double.
Numeric conversion in the conditional operator ? :
In the conditional operator a?b:c, if both b and c are different numeric types, the following conversion rules are applied at compile time to make their types equal, in order:
The types are converted to their corresponding primitive ones, which is called unboxing.
If one operand were a constant int (not Integer before unboxing) whose value is representable in the other type, the int operand is converted into the other type.
Otherwise the smaller type is converted into the next greater one until both operands have the same type. The conversion orders are:
byte -> short -> int -> long -> float -> double
char -> int -> long -> float -> double
Eventually the whole conditional expression gets the type of its second and third operands.
Examples:
If you combine char with short, the expression becomes int.
If you combine Integer with Integer, the expression becomes Integer.
If you combine final int i = 5 with a Character, the expression becomes char.
If you combine short with float, the expression becomes float.
In the question's example, 200 is converted from Integer into double, 0.0 is unboxed from Double into double and the whole conditional expression becomes becomes double which is eventually boxed into Double because obj is of type Object.
Example:
public static void main(String[] args) {
int i = 10;
int i2 = 10;
long l = 100;
byte b = 10;
char c = 'A';
Long result;
// combine int with int result is int compiler error
// result = true ? i : i2; // combine int with int, the expression becomes int
//result = true ? b : c; // combine byte with char, the expression becomes int
//combine int with long result will be long
result = true ? l : i; // success - > combine long with int, the expression becomes long
result = true ? i : l; // success - > combine int with long, the expression becomes long
result = true ? b : l; // success - > combine byte with long, the expression becomes long
result = true ? c : l; // success - > char long with long, the expression becomes long
Integer intResult;
intResult = true ? b : c; // combine char with byte, the expression becomes int.
// intResult = true ? l : c; // fail combine long with char, the expression becomes long.
}
Related
Could you explain in a detailed manner why the expected result is not correct? As most of the readers expect that the output is Byte Char Int Byte, but of course it is not the correct answer.
public class Tester {
public static String test(byte b) {
return "Byte ";
}
public static String test(char c) {
return "Char ";
}
public static String test(int i) {
return "Int ";
}
public static void main(String[] args) {
byte b = 0;
char c = 'A';
System.out.print(test(true ? b : c));
System.out.print(test(false ? b : c));
System.out.print(test(true ? 0 : 'A'));
System.out.print(test(false ? 'A' : (byte)0));
}
}
The correct result is Int Int Char Int.
This is because overload resolution depends on the compile-time type of the argument expressions, not the runtime type of the argument. See JLS 15.12.2.2:
The argument expression true ? b : c has the type int, so the Int method is called. This is specified in the JLS 15.25.2, where it is said that if none of the special cases match (none of them do here), then the type of the conditional expression is the type after applying numeric promotion to the second and third operands:
An expression appears in a numeric choice context if the expression is one of the following:
The second or third operand of a numeric conditional expression
[...]
Numeric promotion determines the promoted type of all the expressions in a numeric context. [...] The rules are as follows:
[...] (none of these rules match in the case of a short and a byte expression)
Otherwise, none of the expressions are of type double, float, or long. In this case, the kind of context determines how the promoted type is chosen.
In a numeric choice context, the following rules apply:
[...] (none of these rules match in the case of a short and a byte expression)
Otherwise, the promoted type is int, and all the expressions that are not of type int undergo widening primitive conversion to int.
This is why true ? b : c is of type int. The same goes for false ? b : c and false ? 'A' : (byte)0. It doesn't matter what the condition is. The type of the expression is determined by the types of the second and third operands.
As for test(true ? 0 : 'A'), this can be explained by a rule that I omitted above, just before the last "Otherwise..."
Otherwise, if any expression is of type char, and every other expression is either of type char or a constant expression of type int with a value that is representable in the type char, then the promoted type is char, and the int expressions undergo narrowing primitive conversion to char.
In this case, the expression "0" is a "a constant expression of type int with a value that is representable in the type char".
One way to think about the type of a conditional expression, is that it's the smallest type that the expressions of both of the branches can "fit". For a byte b and a char c, int is the smallest type that can fit both of them. For 0, and 'A', char is enough to fit both, as it is known that 0 is in the range of char.
For the type of a conditional expression in Java, always consult the JLS charts (Section 15.25).
3rd →
byte
short
char
int
2nd ↓
byte
byte
short
bnp(byte,char)
byte | bnp(byte,int)
Byte
byte
short
bnp(Byte,char)
byte | bnp(Byte,int)
short
short
short
bnp(short,char)
short | bnp(short,int)
Short
short
short
bnp(Short,char)
short | bnp(Short,int)
char
bnp(char,byte)
bnp(char,short)
char
char | bnp(char,int)
where the notation "bnp(x, y)" means the type that is the result of binary numeric promotion of x and y, and the form "T | bnp(..)" means that if one operand is a constant expression of type int and may be representable in type T, then binary numeric promotion is used if the operand is not representable in type T.
For the first 2 calls, we have a char and a byte, so the result is "bnp(byte, char)", or the type int.
For the third call, we have a constant expression of type int and a char, and the value is representable as a char (it's 0), so the result is the type char.
For the fourth call, we have a byte and a char, so we back to "bnp(byte,char)", which is the type int.
The ternary operator converts its expressions to a common type in order for a variable to store its result.
Imagine if you had an expression like this:
char v = <myCondition> ? 'a' : 0L;
The previous statement would make sense only if the condition was true, but what about if this was false and 0L was to be returned? long and char are not the same data type. So, the compiler needs to find a common type, without losing precision, in order to allow both expressions to be returned and assigned to a variable suitable for both of them. The resulting data type is picked up regardless the condition's outcome.
In this case, long cannot be cast to int and then char as it would lose precision whereas char could be cast to int and then promoted to long. This is why the previous statement can be correctly written like so:
long v = <myCondition> ? 'a' : 0L;
In your example, the first ternary operator has a byte and a char, a byte can be promoted to an int while a char can be cast to an int. The other way around, where a char would be cast to a byte is not possible as this would cause a precision loss (a char occupies two bytes). By applying the same logic of promotion, you can also explain the remaining cases. Except for the third one, where you should apply the resolving table from the previously provided link to the documentation.
Table 15.25-A in the Java language specification describes what type the result of a ?: operator is, depending on the contributing types.
Your first example involves byte and char, so the result is a bnp (binary numeric promotion) of these, and for anything but double, float, or long, the resulting type is int.
Same thing for the others.
This question already has answers here:
Ternary operator casts integer
(3 answers)
Closed 5 years ago.
I recently come accross the scenario where in first syso() charcter is working fine but in second syso() it is printing ASCII code.
public class Test{
public static void main(String[] args) {
char x = 'A';
char y= 'B';
int m = 0;
System.out.println(true ? x : 0);//Working fine prints A
System.out.println(true ? y : 0);//Working fine prints B
System.out.println(false ? 0 : y);//Working fine prints B
System.out.println(false ? m : x);// Here it prints 65 why ?
}
}
I really want to know why it is printing ascii code in second syso() ? Please help
The issue is in the type of false ? m : x, which ends up being int, not char.
As per JLS section 15.25.2 (emphasis and [] note mine):
The type of a numeric conditional expression is determined as follows:
If the second and third operands have the same type, then that is the type of the conditional expression.
...
Otherwise [if none of the above rules hold], binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.
Where binary numeric promotion's relevant rule is (emphasis mine):
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
Therefore in:
char x = ...;
int m = ...;
The expression condition ? m : x is promoted to int, and System.out.println(int) is called, and it prints it as a number.
You'd have to explicitly cast m or the whole expression to a char, e.g.:
System.out.println((char)(false ? m : x));
Or:
System.out.println(false ? (char)m : x);
As for your condition ? x : 0 and condition ? 0 : x forms, one of the rules (that I omitted above) from 15.25.2 is:
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression (§15.28) of type int whose value is representable in type T, then the type of the conditional expression is T.
0 fits this description. x is a char, 0 fits in a char, the type of the conditional is therefore char and the character is printed.
In the following code I have two identical conditional assignment operations, one returns an object of type Double, and the second returns the String "Integer".
double d = 24.0;
Number o = (d % 1 == 0) ? new Double(d).intValue() : new Double(d).doubleValue();
String result = (d % 1 == 0) ? "Integer" : "Double";
System.out.println(o.getClass()); // prints "class java.lang.Double"
System.out.println(result); // Integer
Why are the exact same expressions returning two different things?
Well, that is because of the JLS specs for the conditional operator:
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
...
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the
type of the conditional expression is the promoted type of the second
and third operands.
Numeric promotion is defined here in §5.6.2. It says:
Widening primitive conversion (§5.1.2) is applied to convert either or
both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
...
Well 0.0 is still == to 0
System.out.println(0 == 0.0); // equals true
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
I was just playing around with type casting. Here's the code:
class Typecasting {
public static void main(String[] args) {
byte b = 3;
byte c = b++; // no error
byte d = b + 1; // error
byte e = b + b; // error
}
}
Why is there no error in the first line but in second?? Also when i do
f = b + 2;
I understand that b was automatically cast into int type and therefore f must be int type but when I do
e = b + b;
they both are byte type and their result is also in the range of a byte, so why can't e have byte data type? Is it due to the + binary operator?
Why is there no error in the first line but in second?
Because that's the way the language is defined. There's no byte + byte operator, which is why the third line fails - both operands are promoted to int automatically. From section 15.18.2 of the JLS:
The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.
...
Binary numeric promotion is performed on the operands (§5.6.2).
Now binary numeric promotion always ends up with a value of int, long, float or double... int in this case. So the operation is to add two int values together, and the result is an int.
For b++, however, the type is still byte. It's a postfix increment expression (section 15.14.2):
The type of the postfix increment expression is the type of the variable.
On a related note, this would be okay:
b += 3;
That's a compound assignment (section 15.26.2):
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
Note the casting part, which is why it works.
+(byte, byte) returns an int per the rules of the language.
The relevant section of the spec is §5.6.2:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double,the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
Whereas for ++, the type of the result is the type of the operand. From the JLS, §15.14.2:
The type of the postfix increment expression is the type of the variable.
Thus, for b++, the result is a byte and so is assignable to c.
byte d = b+1;
In here you are assign int value(b+1) to byte d. When you added a int vale to byte value it becomes int value.
byte c = b++; //No error;First Line
This conforms to JLS 15.14.2
The type of the postfix increment expression is the type of the variable. The result of the postfix increment expression is not a variable, but a value.
byte d = b+1; //error;Second Line
byte e = b+b; //error;Third line
This conforms to JLS 15.18.2
The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.
The type of an additive expression on numeric operands is the promoted type of its operands.
If this promoted type is int or long, then integer arithmetic is performed.
Read about type promotion in JLS 5.6.2
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
in line first ++operator returns always operand type result..so it gives no error
in second line here 1 is an integer type because all integer type literals is int by default
in third line +(byte,byte) returns the integer type that why it will forces you to type cast it into int.
--> in third line there is always a probability to overflow in byte type..
* if your byte type is defined as constant then it will not force you to typecast because it will alwayz be in range.
When Java performs a sum, it first "transforms" both operands to int or long (depending of the operands) and the result will be an integer, which will try to assign to your variable of type byte, as it "realizes" the result wont fit in a byte, then it will "complain" and you wont be even able to compile this.
The rules for promotion is "when operands are of different types, automatic binary numeric promotion occurs with the smaller operand type being converted to the larger". But the operands are of same type for example,
byte=byte+byte // Compile time error... found int..
So why is it so?
There's no + operator for byte. Instead, both operands are promoted to int, so you've got
byte = byte + byte
... becomes (widening to find + operator) ...
byte = int + int
... becomes (result of + operator) ...
byte = int
... which then fails because there's no implicit conversion from int to byte. You need to cast:
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);
Here are the actual rules for numeric promotion, from section 5.6.2 of the JLS:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
You were provided with correct answer about automatic promotion to 'int'.
There is one more note about that - compound assignment operators behave as they have an implicit type case. Example:
byte b1 = 1;
byte b2 = 2;
b1 = b1 + b2; // compilation fails
b1 += b2; // compilation successful
I would like to talk about Promotion in general
Java can evaluate only arithmetic expressions in which the operands’ types are identical
For example, in an expression containing int and double values, the int values are promoted to double values for use in the expression.
in another word
double someVar = 1 / 2;// someVar = 0
but
double someVar = (double)1 / 2;// someVar = 0.5
why?
we use the (double) cast operator to create a temporary
floating-point copy of its operand "1" (it's called explicit conversion)
The calculation now consists of a floating-point value (the temporary double copy of 1) divided by the integer 2
according to the above statement, Java performs an operation called promotion (or implicit conversion), so the int values are promoted to double values for use in the expression => the integer 2 is promoted to double
the expression became double someVar = 1.0 / 2.0; // someVar= 0.5
hope this is helpful, even if it is out of the core of the question
To understand this you should refer the 2 things:
Implicit Casting:
byte (8 bit) -> short (16 bit) -> int (32 bit) -> float (32 bit) -> double (64 bit)
char (16 bit) -> int (32 bit)
Arithmetic Operator Rules
Operator Precedence Rule : This rule states that Group of (*,/, %) will be evaluated first. Then Group of (+,-) operator will be evaluated. From a same Group of Operators, calculate from the left.
Operand Promotion Rule : This rule states that Operands having data type smaller than int will be promoted to int. order of promotion (byte->short->int, char->int)
Same Type Operand Rule: This rule states that if both operands are int,long,float,double then the same type is carried to the result type.
i.e. long+long => long , float + float => float, int+int => int
Mix Type Operand Rule : Follow the order of Promotion (int->long->float->double) if any of the operand is from the above order then the smaller will be promoted to the bigger one and result will be calculated in bigger type.
i.e. long + double => double , int + long => long
From this SO question, and above answers due to + arithmetic operator, both operands are converted to type int.
byte b1 = 1;
byte b2 = 2;
byte b3 = b1 + b2; // compile time error
In above code, value of b1 and b2 will be resolved at runtime, so compiler will convert both to int before resolving the value.
But if we consider the following code,
final byte b1 = 1;
final byte b2 = 2;
int b3 = b1 + b2; // constant expression, value resolved at compile time
b1 and b2 are final variables and values will be resolved at compile time so compilation won't fail.