Although it is a very Initial level question but I find it complex one. Actually I want to know what is happening behind the scene? Why Character.MAX_VALUE does not print the Max Value of char(Which is 65535) and MAX_VALUE-1 does.
System.out.println("Byte Max Value: "+Byte.MAX_VALUE);//print 127 Ok!
System.out.println("Character Max Value: "+Character.MAX_VALUE);//print ?(Question Mark)
System.out.println(Character.MAX_VALUE-1);//print 65534
Because in the second line, Character.MAX_VALUE is concatenated with the String.
As the JLS states:
The string concatenation operator + (§15.18.1), which, when given a
String operand and an integral operand, will convert the integral
operand to a String representing its value in decimal form, and then
produce a newly created String that is the concatenation of the two
strings
As Character.MAX_VALUE is not printable, you don't see it.
In the third case, your doing a substraction with an int, thus the whole expression is casted to int and it prints an int value.
Also as the JLS states:
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).
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:
[...]
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.
If you've done
System.out.println("Character Max Value: "+(Character.MAX_VALUE+0));
It would print Character Max Value: 65535
Character.MAX_VALUE is \uFFFF. This is not a printable character by definition. When you perform an operation like -1 or +1 you are changing the type to an int
http://www.fileformat.info/info/unicode/char/ffff/index.htm
Implicit casting by adding 0 to Character.MIN_VALUE or Character.MAX_VALUE works well.
You can also explicitly cast to an int, to get the MIN_VALUE and MAX_VALUE With two println() methods....
System.out.println("char min. value: " + (int)Character.MIN_VALUE);
System.out.println("char max. value: " + (int)Character.MAX_VALUE);
In your third line you have...
System.out.println(Character.MAX_VALUE-1);//print 65534
You are essentially implicitly casting the Unicode maximum value to an int and then subtracting 1 from that maximum value. In Unicode format the range is from U+0000 to U+FFFF, the FFFF (65535) is the numeric upper range of the char primitive data type and 0000 (0) is the numeric lower range of the char data type. In the two println() methods above, is the Character class which is the wrapper class for the char primitive data type, it simply takes the primitive char and wraps it up in the Character class. Allowing us to treat it as an object and giving us access to the fields and methods of the Character wrapper class.
Then using the MIN_VALUE and MAX_VALUE fields with the dot operator we can cast these Unicode values to int's and the output is the range expressed as decimal numbers is 0 to 65535
Of course it is understood that if something can be implicitly cast it can also be explicitly cast.
We are also only considering here the Basic Multilingual Plane (Plane 0). Normally a Unicode code point is referred to by writing "U+" followed by its four digit hexadecimal number. So these code points in Plane 0 are expressed by a four digit hexadecimal number, nothing to difficult. The Unicode code points are nothing more than four digit hexadecimal numbers. Plane 0 has a range of 65535 possible characters that it can represent. Wikipedia has a good article on Unicode.
http://en.wikipedia.org/wiki/Unicode
Related
Is there any difference between how type conversion happens in case of positive and negative numbers?
For example, if we have
short a = 100;
and put it to
int b = a;
if we change '100' to '-100', does it make any difference?
I tried to find it compiling in IDEA, but didn't find difference, but I have this questions from my mentor.
Disclaimer: Since this is a homework question, what I say here might not be the "expected" answer.
There are two conversions involved here. The first one is a narrowing primitive conversion from int (the literal 100 evaluates to a value of type int) to short. The second one is a widening primitive conversion from short to int.
The second conversion will never lose information, as per the JLS §5.1.2:
A widening primitive conversion does not lose information about the
overall magnitude of a numeric value in the following cases, where the
numeric value is preserved exactly:
from an integral type to another integral type
from byte, short, or char to a floating point type
from int to double
from float to double in a strictfp expression (§15.4)
The first conversion is done like this, according to the JLS §5.1.3
A narrowing conversion of a signed integer to an integral type T
simply discards all but the n lowest order bits, where n is the number
of bits used to represent type T. In addition to a possible loss of
information about the magnitude of the numeric value, this may cause
the sign of the resulting value to differ from the sign of the input
value.
Both -100 and 100 is representable with short, whose range is -65536...65535, so no information is lost here either.
In short, it doesn't matter whether you use 100 or -100, the result will be that b will store the value of 100 or -100 respectively.
Why doe it happen the following:
char p = 0;
p--;
System.out.println(p);
result 65535
Why does not give it out a compilation error or a runtime Exception?
I expected it as chars cannot be negative. Instead it starts back counting from upside down.
Thanks in advance.
Why does not give it out a compilation error or a runtime Exception?
Because the language specification mandates that arithmetic on primitive types is modulo 2^width, so -1 becomes 2^16-1 as a char.
In the section on integer operations, it is stated that
The built-in integer operators do not indicate overflow or underflow in any way.
so that forbids throwing an exception.
For the postfix-decrement operator used, specifically, its behaviour is specified in 15.14.3
Otherwise, the value 1 is subtracted from the value of the variable and the difference is stored back into the variable. Before the subtraction, binary numeric promotion (§5.6.2) is performed on the value 1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the postfix decrement expression is the value of the variable before the new value is stored.
The binary numeric promotion converts both, the value and 1, to int (since the type here is char), thus you have the intermediate result -1 as an int, then the narrowing primitive conversion is performed:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
resulting in a char value of 0xFFFF (since Java specifies two's complement representation for its signed integer types, explicitly stated in the specification of unary minus):
For integer values, negation is the same as subtraction from zero. The Java programming language uses two's-complement representation for integers, and the range of two's-complement values is not symmetric, so negation of the maximum negative int or long results in that same maximum negative number. Overflow occurs in this case, but no exception is thrown. For all integer values x, -x equals (~x)+1.
For the general wrap-around behaviour for out-of-range results, as an example in the specification of the multiplication operator:
If an integer multiplication overflows, then the result is the low-order bits of the mathematical product as represented in some sufficiently large two's-complement format. As a result, if overflow occurs, then the sign of the result may not be the same as the sign of the mathematical product of the two operand values.
Similar phrases occur in the specification of integer addition, and subtraction is required to fulfill a - b == a + (-b), so the overflow behaviour follows.
Because that's how the Java language is defined. The runtime doesn't check bounds at each operation (probably because it would be extremely expensive). It just overflows or underflows.
Why doe it happen the following:
char p = 0;
p--;
System.out.println(p);
result 65535
Why does not give it out a compilation error or a runtime Exception?
I expected it as chars cannot be negative. Instead it starts back counting from upside down.
Thanks in advance.
Why does not give it out a compilation error or a runtime Exception?
Because the language specification mandates that arithmetic on primitive types is modulo 2^width, so -1 becomes 2^16-1 as a char.
In the section on integer operations, it is stated that
The built-in integer operators do not indicate overflow or underflow in any way.
so that forbids throwing an exception.
For the postfix-decrement operator used, specifically, its behaviour is specified in 15.14.3
Otherwise, the value 1 is subtracted from the value of the variable and the difference is stored back into the variable. Before the subtraction, binary numeric promotion (§5.6.2) is performed on the value 1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the postfix decrement expression is the value of the variable before the new value is stored.
The binary numeric promotion converts both, the value and 1, to int (since the type here is char), thus you have the intermediate result -1 as an int, then the narrowing primitive conversion is performed:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
resulting in a char value of 0xFFFF (since Java specifies two's complement representation for its signed integer types, explicitly stated in the specification of unary minus):
For integer values, negation is the same as subtraction from zero. The Java programming language uses two's-complement representation for integers, and the range of two's-complement values is not symmetric, so negation of the maximum negative int or long results in that same maximum negative number. Overflow occurs in this case, but no exception is thrown. For all integer values x, -x equals (~x)+1.
For the general wrap-around behaviour for out-of-range results, as an example in the specification of the multiplication operator:
If an integer multiplication overflows, then the result is the low-order bits of the mathematical product as represented in some sufficiently large two's-complement format. As a result, if overflow occurs, then the sign of the result may not be the same as the sign of the mathematical product of the two operand values.
Similar phrases occur in the specification of integer addition, and subtraction is required to fulfill a - b == a + (-b), so the overflow behaviour follows.
Because that's how the Java language is defined. The runtime doesn't check bounds at each operation (probably because it would be extremely expensive). It just overflows or underflows.
This loop will continue indefinitely:
char a = 100;
for(a=100; a>=0;--a)
System.out.println(a);
Does it happen because a gets promoted to an int value for arithmetic operations and gets widened to 32 bits from 16 bit char value and hence will always stay positive?
It will indeed loop indefinitely -- and the reason you stated is close. It happens because a can't represent any number that doesn't satisfy a >= 0 -- char is unsigned. Arithmetic underflow is well-defined in Java and unindicated. See the below relevant parts of the specification.
§4.2.2
The integer operators do not indicate overflow or underflow in any way.
This means there is no indication of overflow/underflow other than just comparing the values... e.g. if a <= --a, then that means an underflow occured.
§15.15.2
Before the subtraction, binary numeric promotion (§5.6.2) is performed on the value 1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the prefix decrement expression is the value of the variable after the new value is stored.
So, we can see that there are two major steps here: binary numeric promotion, followed by a narrowing pritimive conversion.
§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.
We can see that the decrement expression works with a treated as int, thus performing a widening conversion. This allows it to represent the value -1.
§5.1.3
A narrowing primitive conversion may lose information about the overall magnitude of a numeric value and may also lose precision and range.
...
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
Keeping only the n lowest order bits means that only the lowest 16 bits of the int expression a - 1 are kept. Since -1 is 0b11111111 11111111 11111111 11111111 here, only the lower 0b11111111 11111111 is saved. Since char is unsigned, all of these bits contribute to the result, giving 65535.
Noticing something here? Essentially, this all means that Java integer arithmetic is modular; in this case, the modulus is 2^16, or 65536, because char is a 16-bit datatype. -1 (mod 65536) ≡ 65535, so the decrement will wrap back around.
Nope. char values are unsigned - when they go below 0, they come back around to 65535.
Swap char with byte - then it'll work.
As others have said, the char type in Java is unsigned, so a >= 0 will always be true. When a hits 0 and then is decremented once more, it becomes 65535. If you just want to be perverse, you can write your loop to terminate after 101 iterations this way:
char a = 100;
for(a=100; a<=100;--a)
System.out.println(a);
Code reviewers can then have a field day tearing you apart for writing such a horrible thing. :)
Why its printing X88
public static void main(String [] args)
{
char x = 'X';
int i = 0;
System.out.print(true ? x : 0);
System.out.print(false ? i : x);
}
In the first print statement, the type of the conditional expression is char (i.e. 'X') because this part of section 15.25 of the JLS (which is about the type of a conditional expression) applies:
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.
So the first statement prints "X".
In the second print statement, that part doesn't apply because i isn't a constant expression. Instead, this section applies:
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).
Binary numeric promotion converts the char 'X' to an int (88) and the second statement prints "88" - hence the overall result of "X88".
It's explained in §15.25 of the JLS.
Otherwise, if the second and third
operands have types that are
convertible (§5.1.8) to numeric types,
then there are several cases:
This applies to both statements, since both char and int are numeric types, and thus 5.1.8 trivially applies. So we look at the rules below (excerpted):
[...]
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.
This applies to the first, since 0 is a constant expression of type int. T is , char, which is why it prints as X.
[...]
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).
This applies to the second, since nothing else does. :) The relevant rule from §5.6.2 is simply:
Otherwise, both operands are converted to type int.
The Unicode code point for 'X' is 88.
For the first statement System.out.print(false ? x : 0); the compiler thinks that you want to print a char so 0 will be considered as a char (during compilation).
When you do System.out.print(false ? i : x); the compiler thinks that you want to print an integer, so it will try to convert (widen) 'X' into an integer which is 88.
An interesting thing is that if you try to do this :
System.out.print(true ? x : i);
As i cannot be considered as a char (it would require narrowing) it will print 88
Another thing which is interessant here :
System.out.print(true ? x : 65536);
This time the value 65536 can't be considered as a char at compile time (the max value for a char is 65535 [#See Character.MAX_VALUE]) so it will be considered as an int, so x will be too.
To summarize, if one of the operand is an int and the other a char, there are two possible conversions :
The int is narrowed into a char (loss of precision)
The char is widen into an int (no loss of precision)
To avoid useless loss, Java will chose the second option.
When you do System.out.print(false ? x : 0);, the 0 is converted at compilation time into a char (because the compiler knows that there won't be loss of precision).
Resources :
JLS - Widening Primitive Conversion
Because the expression false ? i : x is being seen as returning an integer by the compiler. Since you are using a char the 'X' is 88 in ASCII and it is being seen as an integer since they are compatible.
Personally, I think there should be at least a compiler warning here.
In the second ternary If, the parameters must be of the same type, otherwise one of the two is implicitly converted.
In your example, x is converted from char to int, and 'X' has an ASCII code of 88.
Others have already answered why this happens.
If you want X to be printed, cast the expression value back to char as:
System.out.print((char)(false ? i : x)); // prints X
or you can also cast i to char so that the type of expression becomes char as:
System.out.print(false ? (char)i : x); // prints X