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.
Related
I am trying to convert a signed byte in unsigned. The problem is the data I am receiving is unsigned and Java does not support unsigned byte, so when it reads the data it treats it as signed.
I tried it to convert it by the following solution I got from Stack Overflow.
public static int unsignedToBytes(byte a)
{
int b = a & 0xFF;
return b;
}
But when again it's converted in byte, I get the same signed data. I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter, so I can't use any other data type. How can I fix this problem?
The fact that primitives are signed in Java is irrelevant to how they're represented in memory / transit - a byte is merely 8 bits and whether you interpret that as a signed range or not is up to you. There is no magic flag to say "this is signed" or "this is unsigned".
As primitives are signed the Java compiler will prevent you from assigning a value higher than +127 to a byte (or lower than -128). However, there's nothing to stop you downcasting an int (or short) in order to achieve this:
int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)
/*
* Will print a negative int -56 because upcasting byte to int does
* so called "sign extension" which yields those bits:
* 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
*
* But you could still choose to interpret this as +200.
*/
System.out.println(b); // "-56"
/*
* Will print a positive int 200 because bitwise AND with 0xFF will
* zero all the 24 most significant bits that:
* a) were added during upcasting to int which took place silently
* just before evaluating the bitwise AND operator.
* So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
* b) were set to 1s because of "sign extension" during the upcasting
*
* 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
* &
* 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
* =======================================
* 0000 0000 0000 0000 0000 0000 1100 1000 (200)
*/
System.out.println(b & 0xFF); // "200"
/*
* You would typically do this *within* the method that expected an
* unsigned byte and the advantage is you apply `0xFF` only once
* and than you use the `unsignedByte` variable in all your bitwise
* operations.
*
* You could use any integer type longer than `byte` for the `unsignedByte` variable,
* i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
* it would get casted to `int` anyway.
*/
void printUnsignedByte(byte b) {
int unsignedByte = b & 0xFF;
System.out.println(unsignedByte); // "200"
}
I'm not sure I understand your question.
I just tried this and for byte -12 (signed value) it returned integer 244 (equivalent to unsigned byte value but typed as an int):
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
public static void main(String[] args) {
System.out.println(unsignedToBytes((byte) -12));
}
Is it what you want to do?
Java does not allow to express 244 as a byte value, as would C. To express positive integers above Byte.MAX_VALUE (127) you have to use a different integral type, like short, int or long.
Complete guide for working with unsigned bytes in Java:
Unsigned byte in Java
(Source for this answer.)
The Java Language does not provide anything like the unsigned keyword. A byte according to the language spec represents a value between −128 - 127. For instance, if a byte is cast to an int Java will interpret the first bit as the sign and use sign extension.
That being said, nothing prevents you from viewing a byte simply as 8 bits and interpret those bits as a value between 0 and 255. Just keep in mind that there's nothing you can do to force your interpretation upon someone else's method. If a method accepts a byte, then that method accepts a value between −128 and 127 unless explicitly stated otherwise.
Here are a couple of useful conversions / manipulations for your convenience:
Conversions to / from int
// From int to unsigned byte
int i = 200; // some value between 0 and 255
byte b = (byte) i; // 8 bits representing that value
// From unsigned byte to int
byte b = 123; // 8 bits representing a value between 0 and 255
int i = b & 0xFF; // an int representing the same value
(Or, if you're on Java 8+, use Byte.toUnsignedInt.)
Parsing / formatting
Best way is to use the above conversions:
// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");
// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));
Arithmetics
The 2-complement representation "just works" for addition, subtraction and multiplication:
// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;
byte sum = (byte) (b1 + b2); // 215
byte diff = (byte) (b1 - b2); // 185
byte prod = (byte) (b2 * b2); // 225
Division requires manual conversion of operands:
byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
There are no primitive unsigned bytes in Java. The usual thing is to cast it to bigger type:
int anUnsignedByte = (int) aSignedByte & 0xff;
I think the other answers have covered memory representation and how you handle these depends on the context of how you plan on using it. I'll add that Java 8 added some support for dealing with unsigned types. In this case, you could use Byte.toUnsignedInt
int unsignedInt = Byte.toUnsignedInt(myByte);
A side note, if you want to print it out, you can just say
byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
You can also:
public static int unsignedToBytes(byte a)
{
return (int) ( ( a << 24) >>> 24);
}
Explanation:
let's say a = (byte) 133;
In memory it's stored as: "1000 0101" (0x85 in hex)
So its representation translates unsigned=133, signed=-123 (as 2's complement)
a << 24
When left shift is performed 24 bits to the left, the result is now a 4 byte integer which is represented as:
"10000101 00000000 00000000 00000000" (or "0x85000000" in hex)
then we have
( a << 24) >>> 24
and it shifts again on the right 24 bits but fills with leading zeros. So it results to:
"00000000 00000000 00000000 10000101" (or "0x00000085" in hex)
and that is the unsigned representation which equals to 133.
If you tried to cast a = (int) a;
then what would happen is it keeps the 2's complement representation of byte and stores it as int also as 2's complement:
(int) "10000101" ---> "11111111 11111111 11111111 10000101"
And that translates as: -123
Although it may seem annoying (coming from C) that Java did not include unsigned byte in the language it really is no big deal since a simple "b & 0xFF" operation yields the unsigned value for (signed) byte b in the (rare) situations that it is actually needed. The bits don't actually change -- just the interpretation (which is important only when doing for example some math operations on the values).
If think you are looking for something like this.
public static char toUnsigned(byte b) {
return (char) (b >= 0 ? b : 256 + b);
}
Adamski provided the best answer, but it is not quite complete, so read his reply, as it explains the details I'm not.
If you have a system function that requires an unsigned byte to be passed to it, you can pass a signed byte as it will automatically treat it as an unsigned byte.
So if a system function requires four bytes, for example, 192 168 0 1 as unsigned bytes you can pass -64 -88 0 1, and the function will still work, because the act of passing them to the function will un-sign them.
However you are unlikely to have this problem as system functions are hidden behind classes for cross-platform compatibility, though some of the java.io read methods return unsighed bytes as an int.
If you want to see this working, try writing signed bytes to a file and read them back as unsigned bytes.
I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter
This is not substantially different from a function accepting an integer to which you want to pass a value larger than 2^32-1.
That sounds like it depends on how the function is defined and documented; I can see three possibilities:
It may explicitly document that the function treats the byte as an unsigned value, in which case the function probably should do what you expect but would seem to be implemented wrong. For the integer case, the function would probably declare the parameter as an unsigned integer, but that is not possible for the byte case.
It may document that the value for this argument must be greater than (or perhaps equal to) zero, in which case you are misusing the function (passing an out-of-range parameter), expecting it to do more than it was designed to do. With some level of debugging support you might expect the function to throw an exception or fail an assertion.
The documentation may say nothing, in which case a negative parameter is, well, a negative parameter and whether that has any meaning depends on what the function does. If this is meaningless then perhaps the function should really be defined/documented as (2). If this is meaningful in an nonobvious manner (e.g. non-negative values are used to index into an array, and negative values are used to index back from the end of the array so -1 means the last element) the documentation should say what it means and I would expect that it isn't what you want it to do anyway.
I happened to accidentally land on this page after wondering about the apparent asymmetry of the netty ByteBuf writeInt and readUnsignedInt methods.
After reading the interesting and educational answers I am still wondering what function you were calling when you said:
I am trying to use this data as a parameter to a function of Java that
accepts only a byte as parameter.
For what it's worth after so many years, here is my fifty cents:
Let's assume the method you are calling is updating some balance with micro amounts and that it behaves according to some well-defined set of requirements. Ie, it is considered to have a correct implementation for its intended behavior:
long processMicroPayment(byte amount) {
this.balance += amount;
return balance;
}
Basically, if you supply a positive amount it will be added to the balance, and a negative amount will effectively be subtracted from the balance. Now because it accepts a byte as its parameter the implicit assumption is that it functionally only accepts amounts between -128 and +127. So if you want to use this method to add, say, 130 to the balance, it simply will not produce the result YOU desire, because there is no way within the implementation of this method to represent an amount higher than 127. So passing it 130 will not result in your desired
behavior. Note that the method has no way of implementing a (say) AmountOutOfBoundsException because 130 will be 'interpreted' as a negative value that is still obeying the method's contract.
So I have the following questions:
are you using the method according to its (implicit or explicit) contract?
is the method implemented correctly?
am I still misunderstanding your question?
There is no unsigned byte in Java, but if you want to display a byte, you can do,
int myInt = 144;
byte myByte = (byte) myInt;
char myChar = (char) (myByte & 0xFF);
System.out.println("myChar :" + Integer.toHexString(myChar));
Output:
myChar : 90
For more information, please check, How to display a hex/byte value in Java.
Yes and no. Ive been digging around with this problem.
Like i understand this:
The fact is that java has signed interger -128 to 127..
It is possible to present a unsigned in java with:
public static int toUnsignedInt(byte x) {
return ((int) x) & 0xff;
}
If you for example add -12 signed number to be unsigned you get 244. But you can use that number again in signed, it has to be shifted back to signed and it´ll be again -12.
If you try to add 244 to java byte you'll get outOfIndexException.
Cheers..
If you have a function which must be passed a signed byte, what do you expect it to do if you pass an unsigned byte?
Why can't you use any other data type?
Unsually you can use a byte as an unsigned byte with simple or no translations. It all depends on how it is used. You would need to clarify what you indend to do with it.
As per limitations in Java, unsigned byte is almost impossible in the current data-type format. You can go for some other libraries of another language for what you are implementing and then you can call them using JNI.
If you want unsigned bytes in Java, just subtract 256 from the number you're interested in. It will produce two's complement with a negative value, which is the desired number in unsigned bytes.
Example:
int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.
You need to use such dirty hacks when using leJOS to program the NXT brick.
I am trying to convert a signed byte in unsigned. The problem is the data I am receiving is unsigned and Java does not support unsigned byte, so when it reads the data it treats it as signed.
I tried it to convert it by the following solution I got from Stack Overflow.
public static int unsignedToBytes(byte a)
{
int b = a & 0xFF;
return b;
}
But when again it's converted in byte, I get the same signed data. I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter, so I can't use any other data type. How can I fix this problem?
The fact that primitives are signed in Java is irrelevant to how they're represented in memory / transit - a byte is merely 8 bits and whether you interpret that as a signed range or not is up to you. There is no magic flag to say "this is signed" or "this is unsigned".
As primitives are signed the Java compiler will prevent you from assigning a value higher than +127 to a byte (or lower than -128). However, there's nothing to stop you downcasting an int (or short) in order to achieve this:
int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)
/*
* Will print a negative int -56 because upcasting byte to int does
* so called "sign extension" which yields those bits:
* 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
*
* But you could still choose to interpret this as +200.
*/
System.out.println(b); // "-56"
/*
* Will print a positive int 200 because bitwise AND with 0xFF will
* zero all the 24 most significant bits that:
* a) were added during upcasting to int which took place silently
* just before evaluating the bitwise AND operator.
* So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
* b) were set to 1s because of "sign extension" during the upcasting
*
* 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
* &
* 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
* =======================================
* 0000 0000 0000 0000 0000 0000 1100 1000 (200)
*/
System.out.println(b & 0xFF); // "200"
/*
* You would typically do this *within* the method that expected an
* unsigned byte and the advantage is you apply `0xFF` only once
* and than you use the `unsignedByte` variable in all your bitwise
* operations.
*
* You could use any integer type longer than `byte` for the `unsignedByte` variable,
* i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
* it would get casted to `int` anyway.
*/
void printUnsignedByte(byte b) {
int unsignedByte = b & 0xFF;
System.out.println(unsignedByte); // "200"
}
I'm not sure I understand your question.
I just tried this and for byte -12 (signed value) it returned integer 244 (equivalent to unsigned byte value but typed as an int):
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
public static void main(String[] args) {
System.out.println(unsignedToBytes((byte) -12));
}
Is it what you want to do?
Java does not allow to express 244 as a byte value, as would C. To express positive integers above Byte.MAX_VALUE (127) you have to use a different integral type, like short, int or long.
Complete guide for working with unsigned bytes in Java:
Unsigned byte in Java
(Source for this answer.)
The Java Language does not provide anything like the unsigned keyword. A byte according to the language spec represents a value between −128 - 127. For instance, if a byte is cast to an int Java will interpret the first bit as the sign and use sign extension.
That being said, nothing prevents you from viewing a byte simply as 8 bits and interpret those bits as a value between 0 and 255. Just keep in mind that there's nothing you can do to force your interpretation upon someone else's method. If a method accepts a byte, then that method accepts a value between −128 and 127 unless explicitly stated otherwise.
Here are a couple of useful conversions / manipulations for your convenience:
Conversions to / from int
// From int to unsigned byte
int i = 200; // some value between 0 and 255
byte b = (byte) i; // 8 bits representing that value
// From unsigned byte to int
byte b = 123; // 8 bits representing a value between 0 and 255
int i = b & 0xFF; // an int representing the same value
(Or, if you're on Java 8+, use Byte.toUnsignedInt.)
Parsing / formatting
Best way is to use the above conversions:
// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");
// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));
Arithmetics
The 2-complement representation "just works" for addition, subtraction and multiplication:
// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;
byte sum = (byte) (b1 + b2); // 215
byte diff = (byte) (b1 - b2); // 185
byte prod = (byte) (b2 * b2); // 225
Division requires manual conversion of operands:
byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
There are no primitive unsigned bytes in Java. The usual thing is to cast it to bigger type:
int anUnsignedByte = (int) aSignedByte & 0xff;
I think the other answers have covered memory representation and how you handle these depends on the context of how you plan on using it. I'll add that Java 8 added some support for dealing with unsigned types. In this case, you could use Byte.toUnsignedInt
int unsignedInt = Byte.toUnsignedInt(myByte);
A side note, if you want to print it out, you can just say
byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
You can also:
public static int unsignedToBytes(byte a)
{
return (int) ( ( a << 24) >>> 24);
}
Explanation:
let's say a = (byte) 133;
In memory it's stored as: "1000 0101" (0x85 in hex)
So its representation translates unsigned=133, signed=-123 (as 2's complement)
a << 24
When left shift is performed 24 bits to the left, the result is now a 4 byte integer which is represented as:
"10000101 00000000 00000000 00000000" (or "0x85000000" in hex)
then we have
( a << 24) >>> 24
and it shifts again on the right 24 bits but fills with leading zeros. So it results to:
"00000000 00000000 00000000 10000101" (or "0x00000085" in hex)
and that is the unsigned representation which equals to 133.
If you tried to cast a = (int) a;
then what would happen is it keeps the 2's complement representation of byte and stores it as int also as 2's complement:
(int) "10000101" ---> "11111111 11111111 11111111 10000101"
And that translates as: -123
Although it may seem annoying (coming from C) that Java did not include unsigned byte in the language it really is no big deal since a simple "b & 0xFF" operation yields the unsigned value for (signed) byte b in the (rare) situations that it is actually needed. The bits don't actually change -- just the interpretation (which is important only when doing for example some math operations on the values).
If think you are looking for something like this.
public static char toUnsigned(byte b) {
return (char) (b >= 0 ? b : 256 + b);
}
Adamski provided the best answer, but it is not quite complete, so read his reply, as it explains the details I'm not.
If you have a system function that requires an unsigned byte to be passed to it, you can pass a signed byte as it will automatically treat it as an unsigned byte.
So if a system function requires four bytes, for example, 192 168 0 1 as unsigned bytes you can pass -64 -88 0 1, and the function will still work, because the act of passing them to the function will un-sign them.
However you are unlikely to have this problem as system functions are hidden behind classes for cross-platform compatibility, though some of the java.io read methods return unsighed bytes as an int.
If you want to see this working, try writing signed bytes to a file and read them back as unsigned bytes.
I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter
This is not substantially different from a function accepting an integer to which you want to pass a value larger than 2^32-1.
That sounds like it depends on how the function is defined and documented; I can see three possibilities:
It may explicitly document that the function treats the byte as an unsigned value, in which case the function probably should do what you expect but would seem to be implemented wrong. For the integer case, the function would probably declare the parameter as an unsigned integer, but that is not possible for the byte case.
It may document that the value for this argument must be greater than (or perhaps equal to) zero, in which case you are misusing the function (passing an out-of-range parameter), expecting it to do more than it was designed to do. With some level of debugging support you might expect the function to throw an exception or fail an assertion.
The documentation may say nothing, in which case a negative parameter is, well, a negative parameter and whether that has any meaning depends on what the function does. If this is meaningless then perhaps the function should really be defined/documented as (2). If this is meaningful in an nonobvious manner (e.g. non-negative values are used to index into an array, and negative values are used to index back from the end of the array so -1 means the last element) the documentation should say what it means and I would expect that it isn't what you want it to do anyway.
I happened to accidentally land on this page after wondering about the apparent asymmetry of the netty ByteBuf writeInt and readUnsignedInt methods.
After reading the interesting and educational answers I am still wondering what function you were calling when you said:
I am trying to use this data as a parameter to a function of Java that
accepts only a byte as parameter.
For what it's worth after so many years, here is my fifty cents:
Let's assume the method you are calling is updating some balance with micro amounts and that it behaves according to some well-defined set of requirements. Ie, it is considered to have a correct implementation for its intended behavior:
long processMicroPayment(byte amount) {
this.balance += amount;
return balance;
}
Basically, if you supply a positive amount it will be added to the balance, and a negative amount will effectively be subtracted from the balance. Now because it accepts a byte as its parameter the implicit assumption is that it functionally only accepts amounts between -128 and +127. So if you want to use this method to add, say, 130 to the balance, it simply will not produce the result YOU desire, because there is no way within the implementation of this method to represent an amount higher than 127. So passing it 130 will not result in your desired
behavior. Note that the method has no way of implementing a (say) AmountOutOfBoundsException because 130 will be 'interpreted' as a negative value that is still obeying the method's contract.
So I have the following questions:
are you using the method according to its (implicit or explicit) contract?
is the method implemented correctly?
am I still misunderstanding your question?
There is no unsigned byte in Java, but if you want to display a byte, you can do,
int myInt = 144;
byte myByte = (byte) myInt;
char myChar = (char) (myByte & 0xFF);
System.out.println("myChar :" + Integer.toHexString(myChar));
Output:
myChar : 90
For more information, please check, How to display a hex/byte value in Java.
Yes and no. Ive been digging around with this problem.
Like i understand this:
The fact is that java has signed interger -128 to 127..
It is possible to present a unsigned in java with:
public static int toUnsignedInt(byte x) {
return ((int) x) & 0xff;
}
If you for example add -12 signed number to be unsigned you get 244. But you can use that number again in signed, it has to be shifted back to signed and it´ll be again -12.
If you try to add 244 to java byte you'll get outOfIndexException.
Cheers..
If you have a function which must be passed a signed byte, what do you expect it to do if you pass an unsigned byte?
Why can't you use any other data type?
Unsually you can use a byte as an unsigned byte with simple or no translations. It all depends on how it is used. You would need to clarify what you indend to do with it.
As per limitations in Java, unsigned byte is almost impossible in the current data-type format. You can go for some other libraries of another language for what you are implementing and then you can call them using JNI.
If you want unsigned bytes in Java, just subtract 256 from the number you're interested in. It will produce two's complement with a negative value, which is the desired number in unsigned bytes.
Example:
int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.
You need to use such dirty hacks when using leJOS to program the NXT brick.
I need to sum all data bytes in ByteArrayOutputStream, adding +1 to the result and taking the 2 least significant bytes.
int checksum = 1;
for(byte b : byteOutputStream.toByteArray()) {
checksum += b;
}
Any input on taking the 2 least significant bytes would be helpful. Java 8 is used in the environment.
If you really mean least significant bytes then:
checksum & 0xFFFF
If you meant that you want to take least significant bits from checksum, then:
checksum & 0x3
Add
checksum &= 0x0000ffff;
That will zero out everything to the left of the 2 least significant bytes.
Your question is a bit underspecified. You didn’t say neither, what you want to do with these two bytes nor how you want to store them (which depends on what you want to do).
To get to individual bytes, you can use
byte lowest = (byte)checksum, semiLowest=(byte)(checksum>>8);
In case you want to store them in a single integer variable, you have to decide, how these bytes are to be interpreted numerically, i.e signed or unsigned.
If you want a signed interpretation, the operation is as simple as
short lowest2bytes = (short)checksum;
If you want an unsigned interpretation, there’s the obstacle that Java has no dedicated type for that. There is a 2 byte sized unsigned type (char), but using it for numerical values can cause confusion when other code tries to interpret it as character value (i.e. when printing). So in that case, the best solution is to use an int variable again and only initialize it with the unsigned char value:
int lowest2bytes = (char)checksum;
Note that this is semantically equivalent to
int lowest2bytes = checksum&0xffff;
seen in other solutions.
How come this happens:
char a = '\uffff'; //Highest value that char can take - 65535
byte b = (byte)a; //Casting a 16-bit value into 8-bit data type...! Isn't data lost here?
char c = (char)b; //Let's get the value back
int d = (int)c;
System.out.println(d); //65535... how?
Basically, I saw that a char is 16-bit. Therefore, if you cast it into a byte, how come no data is lost? (Value is the same after casting into an int)
Thanks in advance for answering this little ignorant question of mine. :P
EDIT: Woah, found out that my original output actually did as expected, but I just updated the code above. Basically, a character is cast into a byte and then cast back into a char, and its original, 2-byte value is retained. How does this happen?
As trojanfoe states, your confusion on the results of your code is partly due to sign-extension. I'll try to add a more detailed explanation that may help with your confusion.
char a = '\uffff';
byte b = (byte)a; // b = 0xFF
As you noted, this DOES result in the loss of information. This is considered a narrowing conversion. Converting a char to a byte "simply discards all but the n lowest order bits".
The result is: 0xFFFF -> 0xFF
char c = (char)b; // c = 0xFFFF
Converting a byte to a char is considered a special conversion. It actually performs TWO conversions. First, the byte is SIGN-extended (the new high order bits are copied from the old sign bit) to an int (a normal widening conversion). Second, the int is converted to a char with a narrowing conversion.
The result is: 0xFF -> 0xFFFFFFFF -> 0xFFFF
int d = (int)c; // d = 0x0000FFFF
Converting a char to an int is considered a widening conversion. When a char type is widened to an integral type, it is ZERO-extended (the new high order bits are set to 0).
The result is: 0xFFFF -> 0x0000FFFF. When printed, this will give you 65535.
The three links I provided are the official Java Language Specification details on primitive type conversions. I HIGHLY recommend you take a look. They are not terribly verbose (and in this case relatively straightforward). It details exactly what java will do behind the scenes with type conversions. This is a common area of misunderstanding for many developers. Post a comment if you are still confused with any step.
It's sign extension. Try \u1234 instead of \uffff and see what happens.
java byte is signed. it's counter intuitive. in almost all situations where a byte is used, programmers would want an unsigned byte instead. it's extremely likely a bug if a byte is cast to int directly.
This does the intended conversion correctly in almost all programs:
int c = 0xff & b ;
Empirically, the choice of signed byte is a mistake.
Some rather strange stuff going on your machine. Take a look at Java language specification, chapter 4.2.1:
The values of the integral types are
integers in the following ranges:
For byte, from -128 to 127, inclusive
... snip others...
If your JVM is standards compliant, then your output should be -1.
//key & hash are both byte[]
int leftPos = 0, rightPos = 31;
while(leftPos < 16) {
//possible loss of precision. required: byte, found: int
key[leftPos] = hash[leftPos] ^ hash[rightPos];
leftPos++;
rightPos--;
}
Why would a bitwise operation on two bytes in Java return an int? I know I could just cast it back to byte, but it seems silly.
Because the language spec says so. It gives no reason, but I suspect that these are the most likely intentions:
To have a small and simple set of rules to cover arithmetic operations involving all possible combinations of types
To allow an efficient implementation - 32 bit integers are what CPUs use internally, and everything else requires conversions, explicit or implicit.
If it's correct and there are no value that can cause this loss of precision, in other words : "impossible loss of precision" the compiler should shut up ... and need to be corrected, and no cast should be added in this :
byte a = (byte) 0xDE;
byte b = (byte) 0xAD;
byte r = (byte) ( a ^ b);
There is no Java bitwise operations on two bytes. Your code implicitly and silently converts those bytes to a larger integer type (int), and the result is of that type as well.
You may now question the sanity of leaving bitwise operations on bytes undefined.
This was somewhere down in the answers to one of the similar questions that people have already pointed out:
http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx