//code start
int a=3;
byte b=3;
if(a==b) --> returns true
//code ends
Query :
IT returns true because compares the bits in a and b.
a = 00000011
b = 00000011
here only bit pattern comparison is done and zeros left at the end in int doesn't matter.
what does the above line conveys??
In java automatic type conversion converts any small data type to the larger of the two types. So byte b is converted to int b when you are comparing it with int a.
Do know that double is the largest data type while byte is the smallest.
Rather than only comparing the least significant 8 bits of the two operands like you guessed, the compiler adds 24 0s or (or 1s if the byte is negative) to the byte to make it the same size as the int. This is known as binary numeric promotion and is specified in §5.6.2 of the JLS. The conversion from byte to int is specified in §5.1.2.
Related
Why is it that toHexString prints different strings in what appears to be very specific circumstances? Printing a number below 0x80000000 works just fine. Adding 1 to that value and printing it works fine. But assigning that value directly does not print the same thing, instead I have to add an L to the end.
My guess is that it has to do with the fact that numeric literals are of type int by default, but I don't know this happens at 0x80000000 and not when crossing over 0xffffffff for instance.
long a = 0x7FFFFFFF;
System.out.println(java.lang.Long.toHexString(a)); // prints 7fffffff
a++;
System.out.println(java.lang.Long.toHexString(a)); // prints 80000000
long b = 0x80000000;
System.out.println(java.lang.Long.toHexString(b)); // prints ffffffff80000000
b=0x80000000L;
system.out.println(java.lang.Long.toHexString(b)); // prints 80000000
P.S. Why doesn't oracle or tutorialspoint say anything about how methods are implemented? Where can I find the implementation of the standard libraries?
That has nothing to do with the toHexString method, it's all about int vs long in Java, and binary representation of signed integers.
When you write
long b = 0x7FFFFFFF;
and
long b = 0x80000000;
the literal number on the right is interpreted as an int (32 bits). Now, in the second case that value overflows the (signed) integer positive range, its binary represantion has a 1 in the leftmost position, and hence the number is understood as negative (-2147483648). Afterwards, in the assignment, it's promoted to a (negative) long, so the extra 32 bits are filled with ones. That's why you see those "extra" FFF...
If you don't know about the binary representation of signed integers in Java, read here
In the following program , I am assigning a integer data type to a char data type.
public static void main(String args[]) {
char ch =65;
System.out.println(ch);
}
I know the fact that int occupies 32 bits and char occupies 16 bits . With that knowledge , I was expecting the compiler throw an error of some message "Attempt to convert a data of higher size to a lower size ".
Why is the compiler not complaining and internally converting and printing the output as 'A' (I understand the fact that it is the ASCII equivalent of 65, my question is only related to the size of data types) ?
The compiler does in fact validate the range. That is working because int 65 is within the expected range.
The following won't compile:
char c = (int)Character.MAX_VALUE + 1
char c = 65536
And this will, just like your assignment:
char c = 65535 //Within range
When the value is not a constant at compile time, though, there's need for cast:
private static void charRange(int i) {
char c = (char) i;
System.out.println(" --> " + (int) c);
}
charRange(65);
charRange(Character.MAX_VALUE + 20);
And the check doesn't happen (making room for overflow)
--> 65
--> 19
There is an exception to Java's general rule about converting an int to a char. If the int is a compile time constant expression (e.g. a literal) AND the int value of the expression is within the required range (0 to 65535), then it is legal to assign the int expression to a char.
Intuitively, for a compile-time constant expression, the compiler knows if the expression value can be assigned without loss of information.
This is covered by JLS 5.2 ... in the paragraph that starts "In addition, if the expression is a constant expression ..."
Programing languages like Java or C# come with a set of integer primitive types. Each type has a well-defined range in the form of [min value, max value]. This values are stored in a fixed sequence of bits from most significant bit to the least one.
For example, let the decimal number 123456 be represented for the next 32 bit sequence
0000000000000011110001001000000
When you attempt to convert a 32-bit number type to a 16-bit one, the compiler copies the 16 least significant bits (or the last 16 bits) then 123456 number is wrapped to
1110001001000000
And if you convert this binary number to decimal it is 57920. As you realize, the 32-bit number cant fit into a 16-bit sequence, and the original sequence was arbitrarily wrapped. This is known as integer overflow, and also happens when you add or multiply 2 number which result is out of bounds of the integer type range.
As programmer, you should be aware of overflow, and react to this to avoid a program failure. You also should read further details about signed integer representation.
Here is my program.
public class Foo
{
public static void main(String[] args)
{
System.out.println((int) 2147483648l);
System.out.println((int) 2147483648f);
}
}
Here is the output.
-2147483648
2147483647
Why isn't 2147483648l and 2147483648f type cast to the same integer? Can you explain what is going on here or what concept in Java I need to understand to predict the output of type casts like these?
These are examples of the Narrowing Primitive Conversion operation.
In your first example, long to int:
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.
So your (int) 2147483648l is taking the 64 bits of the long:
00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000
...and dropping the top 32 bits entirely:
10000000 00000000 00000000 00000000
...and taking the remaining 32 bits as an int. Since the leftmost of those is now a sign bit (long and int are stored as two's complement), and since it happens to be set in your 2147483648l value, you end up with a negative number. Since no other bits are set, in two's complement, that means you have the lowest negative number int can represent: -2147483648.
The float to int example follows a more complex rule. The relevant parts for your value are:
...if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V, rounding toward zero using IEEE 754 round-toward-zero mode (§4.2.3).
...[if] the value [is] too large (a positive value of large magnitude or positive infinity), [then] the result of the first step is the largest representable value of type int or long.
(But see the part of the spec linked above for the details.)
So since 2147483648f rounds to 2147483648, and 2147483648 is too large to fit in int, the largest value for int (2147483647) is used instead.
So in the long to int, it's bit fiddling; in the float to int, it's more mathematical.
In a comment you've asked:
Do you know why both (short) 32768 and (short) 32768f evaluate to -32768? I was exepecting the latter to evaluate to 32767.
Excellent question, and that's where my "see the part of the spec linked above for the details" above comes in. :-) (short) 32768f does, in effect, (short)(int)32768f:
In the spec section linked above, under "A narrowing conversion of a floating-point number to an integral type T takes two steps:", it says
In the first step, the floating-point number is converted either to a long, if T is long, or to an int, if T is byte, short, char, or int...
and then later in Step 2's second bullet:
* If T is byte, char, or short, the result of the conversion is the result of a narrowing conversion to type T (§5.1.3) of the result of the first step.
So in step one, 32768f becomes 32768 (an int value), and then of course (short)32768 does the bit-chopping we saw in long => int above, giving us a short value of -32768.
Nice! It's wonderful to see the effects of design decisions presented in the way that you have.
2147483648l is a long type and the rule for converting a long that's too big for the int is to apply the wrap-around rule into the destination type. (Under the hood, the significant bits from the source type are simply discarded.)
2147483648f is a float type and the rule for converting a float that's too big for the destination type is to take the largest possible for the destination type. Reference Are Java integer-type primitive casts "capped" at the MAX_INT of the casting type?
The good thing about standards is that there are so many to choose from.
class A {
public static void main(String [] varun) {
byte b = 65;
char ch = b;
System.out.println(ch);
}
}
Why its give an error:
possible loss of precision
required char
found byte
The error text is misleading.
A char is a 2 byte unsigned type (range 0 to 65535)
A byte is a 1 byte signed type (range -128 to 127).
Therefore a byte cannot be represented in a char in full generality (as you'll lose the negatives). So you get an error; albeit a misleading one.
Byte is 1 byte long, while char is 2 bytes long, so they are incompatible. You need to use casting:
class A
{
public static void main(String [] varun)
{
byte b = 65;
char ch = (char) b;
System.out.println(ch);
}
}
Add as explicit cast as byte just take one byte and char is of two byte in java and implicit type cast does not work with byte and char.
Use
char ch = (char) b;
Your code should be like this:
char ch = (char) b;
The error it gave you it became from the fact that a byte type is an 8-bit integers and chars is 1-bit plus the bits of encoding (UTF-8, ASCII, etc).
The difference between a byte stream and a character stream is that the character stream attempts to work with characters rather than bytes.
So a byte stream is 8-bit stream without encoding. That's why you have this error.
If You are assigned two different type of primitives to each other You may have two types of casting:
if You assign int to long, thus putting smaller type into bigger You perform widening and so called widening conversion - it is also called implicit cast
int a = 100;
long b = a;
on the other hand if You would perform conversion from long to int You are narrowing the type. Thus You need to perform explicit cast if You don't do that You get that possible loss of precision
long a = 100L;
int b = (int)a;
or as in Your case as #Bathsheba said "Therefore a byte cannot be represented in a char in full generality (as you'll lose the negatives). So you get an error; albeit a misleading one." - You need to explicitly cast so that You are aware of loosing data.
When one type of data is assigned to another type of variable, an automatic type conversion
will take place if the following two conditions are met:
• The two types are compatible.
• The destination type is larger than the source type.
When these two conditions are met, a widening conversion takes place.
So the reason for it is,
For widening conversions, the numeric types, including integer and floating-point types,
are compatible with each other. However, there are no automatic conversions from the
numeric types to char or boolean.
The conversion from a byte to a char is a so-called Widening and Narrowing Primitive Conversion (JLS 5.1.4)
First, the byte is converted to an int via widening primitive conversion (§5.1.2), and then the resulting int is converted to a char by narrowing primitive conversion (§5.1.3).
The widening conversion from byte to int is fine (both are signed), but from int to char will loose both sign and (potentially) range (as char is 0 to 65536):
A narrowing primitive conversion may lose information about the overall magnitude of a numeric value and may also lose precision and range.
And
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.
Because of this potential loss of precision, sign and informaiton you get a compilation error and an explicit cast is necessary to signal to the compiler that you know what you're doing.
Given that byte,short and int are signed, why do byte and short in Java not get the usual signed two's complement treatment ? For instance 0xff is illegal for byte.
This has been discussed before here but I couldn't find a reason for why this is the case.
If you look at the actual memory used to store -1 in signed byte, then you will see that it is 0xff. However, in the language itself, rather than the binary representation, 0xff is simply out of range for a byte. The binary representation of -1 will indeed use two's complement but you are shielded from that implementation detail.
The language designers simply took the stance that trying to store 255 in a data type that can only hold -128 to 127 should be considered an error.
You ask in comments why Java allows:
int i = 0xffffffff;
The literal 0xffffffff is an int literal and is interpreted using two's complement. The reason that you cannot do anything similar for a byte is that the language does not provide syntax for specifying that a literal is of type byte, or indeed short.
I don't know why the decision not to offer more literal types was made. I expect it was made for reasons of simplicity. One of the goals of the language was to avoid unnecessary complexity.
You can write
int i = 0xFFFFFFFF;
but you can't write
byte b = 0xFF;
as the 0xFF is an int value not a byte so its equal to 255. There is no way to define a byte or short literal, so you have to cast it.
BTW You can do
byte b = 0;
b += 0xFF;
b ^= 0xFF;
even
byte b = 30;
b *= 1.75; // b = 52.
it is legal, but you need to cast it to byte explicitly, i.e. (byte)0xff because it is out of range.
You can literally set a byte, but surprisingly, you have to use more digits:
byte bad = 0xff; // doesn't work
byte b = 0xffffffff; // fine
The logic is, that 0xff is implicitly 0x000000ff, which exceeds the range of a byte. (255)
It's not the first idea you get, but it has some logic. The longer number is a smaller number (and smaller absolute value).
byte b = 0xffffffff; // -1
byte c = 0xffffff81; // -127
byte c = 0xffffff80; // -128
The possible values for a byte range from -128 to 127.
It would be possible to let values outside the range be assigned to the variable, and silently throw away the overflow, but that would rather be confusing than conventient.
Then we would have:
byte b = 128;
if (b < 0) {
// yes, the value magically changed from 128 to -128...
}
In most situations it's better to have the compiler tell you that the value is outside the range than to "fix" it like that.