byte b = 0xFFFFFFFF; //OK, because integer -1 sits between -128 and 127, FINE!!
char ch = 0xFFFFFFFF; //Not OK, because integer -1 does not sit between 0 and 65535, FINE!!
byte b = 0L; //Compiler says Not OK? But long integer 0 sits between -128 and 127?
I am not convinced with narrowing rule applied by the java compiler in third line of above code.
Please help me understand, the logic behind this narrowing rule.
The L suffix on the literal 0L makes this literal of type long (a 64-bit signed integer).
There is no implicit narrowing from long to byte, according to the rules of the Java language.
See Java Language Specification section 5.2 Assignment Contexts:
In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
Note that the type of the constant expression does not include long.
There are two ways of casting a primitive data type into another. Explicit and Implicit.
Implicit casting as in your case byte b = 0L; gives compilation error as there is a possible loss of information.
If you change it like this:
byte b=(byte)0L;
Then there will be no compiler error, as you are telling compiler explicitely for the conversion.
Related
Consider the below code snippet:
// automatic casting works for int to byte conversion as integer literal 127
// is in the range for byte
byte b1 = 127; //OK
// automatic casting doesn't work for long to int conversion
// even if long literal is in the range of int.
int i5 = 100L; // NOT OK - compilation error
Is there any explanation for such behavior?
Why is explicit conversion not needed in the case of int to byte, but needed for long to int?
The How does Java convert int into byte? question is different. It is about an issue in implicit conversion of int to byte when the int value is out of range.
Widening conversions (eg. byte to int) are generally accepted implicitly by the Java compiler, as there's no loss of information (the range of int is greater than that of byte).
Narrowing conversions (eg. long to int, as in your case) can cause a loss of information, so are generally required to be explicitly casted.
See this similar question, and this. A relevant piece of the Java Language Specification:
Assignment conversion occurs when the value of an expression is assigned (§15.26) to a variable: the type of the expression must be converted to the type of the variable.
...
In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:
Byte and the value of the constant expression is representable in the type byte
Short and the value of the constant expression is representable in the type short.
Character and the value of the constant expression is representable in the type char.
(emphasis mine)
Some confusion stems from the fact that we're dealing in particular with constant expressions, as we're using numeric literals. The above spec also needs some careful reading.
To clear some things up and directly answer some of the OP's queries:
Why implicit narrowing is supported for one type of narrowing and not the other?
Ie. why does byte b1 = 127 work implicitly, while int i5 = 100L not?
byte b1 = 127 performs an implicit conversion as (cf. the bold text in the above quote), "the value of the constant expression is representable in the type byte". That is, 127 is representable by a byte, so the conversion is implicit. If you try byte b1 = 128, you'll get an error about incompatible types, as 128 isn't representable by byte. The only reason we're allowed an implicit cast here at all is because we're using a constant expression.
We don't get an implicit conversion in int i5 = 100L (even though 100 is in the range of int) as that's simply not listed in the allowed implicit conversions (the variable's type, int, is not one of byte, short, or char).
We also don't get an implicit conversion in byte a = 0L, this time as the constant expression is of type long, not of type byte, short, char, or int.
How will a normal programmer know which narrowing conversion is allowed implicitly?
The implicit narrowing conversions only occur when you're assigning a constant expression to a variable. In these cases, implicit conversions are good as we don't want to be writing code like byte b = (byte)0 all the time. At the same time, we do want to be warned if we write something like byte b = 128, as that doesn't have intuitive behaviour.
When we're not assigning constant expressions (so eg. int x = 0; byte b = x;), we always want to be warned when we're doing a potentially lossy conversion, as they're dangerous - so explicit conversions in this case also make sense.
I'm preparing for Java 7 certification and have the following question.
Byte b = 10 compiles ok. Looks like the compiler is narrowing int 10 to byte 10 and then boxing it. How come Byte b = new Byte(10) won't compile? Why can't the compiler narrow int 10 to byte 10 like it did in the first case?
Also how come Long l = new Long(10) compiles ok but Long l = 10 fails?
I'm not clear about how this works. Can somebody provide an clear explanation?
Section 5.2 of the JLS covers the types of conversions that are allowed in assignment contexts.
Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by a widening reference conversion
Additionally,
In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:
Byte and the value of the constant expression is representable in the type byte.
Short and the value of the constant expression is representable in the type short.
Character and the value of the constant expression is representable in the type char.
Byte b = 10 compiles ok because 10 is a constant expression and is representable as a byte.
Byte b = new Byte(10) won't compile because 10 is an int literal, and method invocation conversion won't perform primitive narrowing conversions. To get this call to a Byte constructor to compile, you can explicitly cast 10 to byte:
Byte b = new Byte( (byte) 10);
Long l = new Long(10) compiles because method invocation conversion will perform primitive widening conversions, including from int to long.
Long l = 10 won't compile, because Java will not specifically allow a widening conversion followed by a boxing conversion, as I discussed in a recent answer. To get this to compile, you can use a long literal, so only boxing is necessary.
Long l = 10L;
The basic rules are:
you can't convert-and-autobox in one step (JLS 5.1.7 defines the boxing conversions, and it doesn't include convert-and-autobox type conversions, so they're not allowed)
you can't implicitly narrow a type
These rules explain why Long l = 10 doesn't work, as well as new Byte(10). The first would require the int literal 10 to be widened to a long and then be boxed, which isn't allowed. (More precisely, it would require a conversion from int to Long, which JLS 5.1.7 doesn't define.) The second would require the int literal 10 to be implicitly narrowed to a byte, which isn't allowed.
But there are exceptions to the rule. Byte b = 10 is explicitly allowed by JLS 5.2:
In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:
Byte and the value of the constant expression is representable in the type byte.
(some irrelevant parts omitted)
Lastly, new Long(10) works because the int literal 10 can be automatically widened to a long 10L.
Byte constructor takes either byte type or String type. See this
Constructor for Long takes long as an argument. Since long can take in integer, it allows it in the constructor.
10 is an integer literal, you have to downcast it to pass it to the Byte constructor. There unfortunately is no byte literal syntax to remove the cast either.
Also how come Long l = new Long(10) compiles ok but Long l = 10 fails?
Because 10, an integer, can fit into a long with no issues. An integer cannot fit into a byte, so the cast is needed in that case (widening conversion).
This cast is compile time as well, as it's also a widening conversion. Check out section 5.1.5 in the JLS:
Widening reference conversions never require a special action at run time and therefore never throw an exception at run time. They consist simply in regarding a reference as having some other type in a manner that can be proved correct at compile time.
i think i have a solution for your problem...
//constructor for Byte class
Byte(byte value){
}
There are two rules for java type conversion
Both types are compatible
Destination type is greater than source type
Now in Your case you trying to convert int into byte which is against our second rule....
but below is the solution
Byte b = new Byte((byte)10);
Now let's talk about your Second issue...
Long x = 10;//incompatible type
This is the issue of autoboxing...
Now as we all know that autoboxing automatically converted primitive type into it's wrapper class..
But conversion not happens in case of autoboxing means....int is converted into Integer
byte is converted into Byte..
Now when you assign int primitive type to Long, it gives you error of incompatible type.......
Solution
Long x = (long) 10;//works fine....
Just trying to understand auto-boxing, which I do apart from one thing:
Short s = 250;
Long l = 250;
The assignment to Long l fails. This, I expect, is because you cannot widen then box (i.e. it tries to widen the int value 250 to a long and then box it which it cannot do).
However, the assignment to Short s works. What is going on to make this fine? My assumption was it is still doing boxing and some kind of conversion. But if it's a case of it knowing 250 fits into a short, why does it not know that 250 will fit into a long?
Normally, you cannot apply multiple (implicit) conversions in assignment (JLS §5.2 Assignment Conversion):
Assignment conversion occurs when the value of an expression is assigned (§15.26) to a variable: the type of the expression must be converted to the type of the variable. Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by a widening reference conversion
an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.
Long l=250; requires two conversions (widening primitive conversion followed by boxing conversion), that's why it doesn't compile.
Long l=250l; compiles because it requires a single boxing conversion.
But narrowing conversion of a constant expression is a special case, that's why Short s=250; compiles:
In addition, if the expression is a constant expression (§15.28) of type byte, short, char or int :
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is :
Byte and the value of the constant expression is representable in the type byte.
Short and the value of the constant expression is representable in the type short.
Character and the value of the constant expression is representable in the type char.
Ideally, no auto narrowing should be allowed.
But since there are no byte/short literals, we can't write
byte b = 0b;
and it seems silly to
byte b = (byte)0;
so auto narrowing of constant integer is allowed so we can write
byte b = 0;
which is carried over to autoboxing case.
For long/Long, since there are long literals, this is less of a problem. Still, it should be allowed, since auto widening of signed integer is always safe.
All numbers in Java are supposed to be of int type.
The following line is legal in Java>1.5
Short s = 1; // Will compile to Short s = Short.valueOf((short)1) - thus you can't exceed short max value i.e.
Short s = 4444; // is invalid for autoboxing
Same mechanics go for Integer and Byte instantiation. But Long works completely different. The following code gives compile time error
Long l = 10;
Long uses the same approach for autoboxing of long types, so
Long l = 10L; //is valid and is translated into Long.valueOf(10L)
I can't see why int cannot be assigned to a Long variable. Any thoughts on this matter?
I think the question was not about casting primitives and wrappers in general.
The question was about difference between casting int to java.lang.Long and int to java.lang.Short for example.
JLS:
"In addition, if the expression is a constant expression (§15.28) of type byte, short, char or int:
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:
Byte and the value of the constant expression is representable in the type byte.
Short and the value of the constant expression is representable in the type short.
Character and the value of the constant expression is representable in the type char".
So all <=32bit primitives can be casted easily and long (64bit) requires special casting.
It seems illogically.
All illogical things as usual has explanation in backward compability or historical evolution in java.
E.g. classes Integer and Long exist in java since version 1.0. Classes Short and Byte exist in java since 1.1.
That is at the start point integral number can be two types: integer or long. So I think there are different casting rules for these two types of numbers. And then short and byte were added.
I suppose short and byte can have 32-bit implementation in concrete JVMs.
Because Long with the first capital letter is a wrapper class and not the primitive type .
Take a look here .
You can cast int to long and long to Long
but you can't cast int to Long
it is correct to write Long l = (long) 10;
i had a doubt in assigning or casting to a proper data type.
byte a=3; //compiled
byte b=5; //compiled
byte c=a+b; //not compiled and reporting as possible loss of precision.
here first two statements are compiling even though we are assigning int literal to byte.but what about third statement i am doing the same as above and that too value of a+b is in the range of byte .why there is such error?
The general rule is that you can not use assignment to narrow an integer to a byte, because that is an unsafe narrowing conversion (most ints don't fit in a byte). Specifically, none of the allowed assignment conversions may narrow.
However, there is an exception specifically for this case:
A narrowing primitive conversion may
be used if the type of the variable is
byte, short, or char, and the value of
the constant expression is
representable in the type of the
variable.
This applies to a and b. The type of both variables is byte, and the values of both constant expressions clearly fit in a byte.
When you do the + operation on two bytes, they get implicitly converted to an int, so the result is an int as well. Therefore, you need another cast.
( The literal assignments in the first statement have nothing to do with it. )
I believe that addition performs binary numeric promotion, so a and b are being promoted to ints in the third statement.