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;
Related
Integer literals can be assigned to byte or short variables as long as the value of the literal is within the range of byte/short.
But when long literal is assigned to int variable, compilation error is reported even when the value of long literal is within the range of int.
What is the logic explaining this?
Example,
The below line gets compiled successfully
byte byteVar = 100; //works, here 100 is integer literal.
but
int intVar = 100L; // fails, here 100L is long literal
results in compile time error.
Can someone please explain the underlying logic that drives this.
The actual reason is a bit more complicated than some of the other answers suggest.
JLS 5.2 states the following about the conversions allowed in an assignment context.
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 variable is of type 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 variable is of type Byte, Short, or Character, and
the value of the constant expression is representable in the type
byte, short, or char respectively.
The declaration / initialization
byte byteVar = 100; // OK
works because all of the prerequisites are safisfied:
100 is a constant expression
its type is int
its value is in the range of byte; i.e. it is representable as a byte
it is being assigned to a byte variable.
The declaration / initialization
byte byteVar = 100L; // FAIL
fails because the type of 100L is long rather than int.
The logic for
int intVar = 100L;
not compiling is simply "why would you say L explicitly if you want it to be int? Probably a mistake somewhere, but we don't know if it's the type or the value which is wrong".
The more interesting part is why
byte byteVar = 100;
compiles instead of requiring you to write something like 100b. And I believe there are at least two reasons:
the right part may be a constant expression, not just a literal: in
byte byteVar = SOME_CONST + 3;
you couldn't use a suffix, and the right-hand side is int even if SOME_CONST is byte.
simply that C++ didn't have it and Java inherited a lot from C++.
L means 64-bit int integer primitive.
int intVar = 100L;
The following line will fail to compile because you are trying to place a 64-bit long primitive literal into a 32-bit int variable. It will give : // BAD — compiler fails — Cannot place a 64-bit long int primitive in a 32-bit int variable.
The byte format is an 8-bit integer format that can accept signed integer values in the range -128 to 127. Because the integer value 100 fits within this range,
byte byteVar = 100;
compiles; the integer literal is of a valid scale for what you are trying to store it in. https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html lists default values for the primitive data types and the table shows that byte, short and int all share the same value structure; an integer with nothing else associated to the literal.
The reason the int and 100L does not work is because the L suffix creates a long or Int64 literal. int is Int32, the 32-bit 2's complement signed integer format. By specifying that the value 100 should be of the 64-bit 2's complement signed integer format, this will not fit within 32 bits without an overflow, which is why the compiler does not allow that assignment.
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.
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.
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....
I'm sorry for such a lame-o question. I would test this myself... But unfortunately I do not know how to code for java, and it would not be worth answering just for this one question.
Is it possible to add a long and an integer together?
My friend is working on a project, and I think he can fix one of his errors by using a long instead of an integer. (He wants numbers to be higher than 2.147 billion).
I tried doing a bit of research on my own, and I was surprised that the answer wasn't as easy to find. This is one source of information that I was able to find.
"If either or both of the integer types is a long, the result is a long."
https://community.oracle.com/message/5270213
Is that correct? Again, sorry that I'm not able to test this out myself.
Yes, you can add a long and an int just fine, and you'll end up with a long.
The int undergoes a widening primitive conversion, as described in the Java Language Specification, specifically JLS8, §5.1.2. JLS8 §5.6.2 is the important part that details what happens here (my emphasis):
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.
This remains the case even for the (currently) latest JLS18 spec, in 5.6 Numeric contexts:
If any expression is of a reference type, it is subjected to unboxing conversion (§5.1.8).
Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:
If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.
Otherwise, if any expression is of type long, then the promoted type is long, and other expressions that are not of type long undergo widening primitive conversion to long.
And so on ...
Yes you can add a long and an integer together. in java there are several primitive data types. int and long variables are two of them. these two data types are used to store integer values. the difference is the size of the variable,
int : 32bit
long : 64bit
you can add int and long together, when jvm add these two variables, the result is generated as a long value. so you have to use a long variable to store the answer. This is due to the auto type conversion of java.
if you want to get int value as an answer, you have to cast the long value in to int,
int x=5; //int value
long y = 10; //long value
long z = x + y; //result is a long value(normally jvm does)
int i=(int) (x+y); // result is cast into a int value.
both z and i get value: 15
You can always simply try such things. For instance using jdoodle
As you can see it is perfectly possible. It is advisable to use a long to store the result, but not necessary. In case of overflow in the latter case, Java will simply use the 32 least significant bits, thus:
6666555555555544444444443333333333222222222211111111110000000000 (index)
3210987654321098765432109876543210987654321098765432109876543210
----------------------------------------------------------------
0101010101010010000011110010101111101010101111101011101011011101 (value)
will be stored as:
33222222222211111111110000000000 (index)
10987654321098765432109876543210
--------------------------------
11101010101111101011101011011101 (value)