Java datatype conversions [duplicate] - java

This question already has answers here:
Why are there so many types of number in Java when long and double work every time?
(3 answers)
Closed 7 years ago.
I am a C++ programmer and I am trying to understand the Java datatypes.
Is there anything wrong with the following:
byte: signed 1 byte
short: signed 2 bytes
int: signed 4 bytes
long: signed 8 bytes
float: 4 bytes
double: 8 bytes
boolean: ? bytes
char: unsigned 2 bytes
I can convert anything to a bigger or equal in terms of size datatype, with 1 exception, I can convert from char to 4 or 8 byte variables but I can't convert to char from anything else.
Question: what kind of rules apply when dealing with conversions involving the char datatype?

The implicit data type conversion rules are based on numeric ranges. The char data type is the only unsigned integral type, and it cannot represent the negative values that other numeric types can. For example, -1 can be represented as any numeric type except as char, so there can be no implicit conversion into char.
You can always use an explicit type cast though:
char c = (char) -1;
The range-argument is also why you have an implicit conversion from 64-bit long to the "smaller" 32-bit float.

Related

I have to cast the first two octets from int to byte but not the other octets. Why?

byte[] ipAddr = new byte[] {(byte) 142, (byte) 250,68,46};
I am getting to know the various java net functions and I have to cast the first two octets to a byte in order for it to compile.
Otherwise I get this error
java: incompatible types: possible lossy conversion from int to byte
Any idea why I have to cast specifically the first octets and not all? Why does java take it as an int instead of a byte?
In java, bytes are 8-bit signed datatypes, so the value ranges from -128 to +127. Your first two values are greater than the maximum so you need to manually allow the conversion (by casting, in your case).
Those two octets just happen to be larger than the maximum value allowed in a byte which is 127 (2^7-1). Any value greater than 127 will have to be cast (or dealt with more carefully) and you'll lose data in a straight cast due to the size difference. See here for more: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html#:~:text=Primitive%20values%20do%20not%20share,value%20of%20127%20(inclusive).
#Dennis is on the right track, but the explanation is a bit more complicated than that.
Normally, an int valued expression cannot be assigned to a byte variable without a cast.
When the int valued expression is a constant expression, AND when the value of the expression is within the range of byte, then the assignment to a byte variable is allowed without a cast.
However, this only applies in assignment contexts, and only for constant expressions that satisfy the JLS definition.
In your example, the integer literals are all constant expressions, but the first two are not in the required range for lossless assignment ot a byte; i.e -128 to +127.

In java, how come method read() from FileInputStream works does not throw " incompatible types: possible lossy conversion"?

I am currently going through Java I/O tutorial and having hard time understanding the read() method of FileInputStream class. I know that per documantion that read() method reads "byte" of data from stream and returns an integer representing the byte (between 0 and 256) or -1 if it reaches the end of file.
Byte in java has a range between -128 and 127, so, how come when I edit xanadu.txt and add ASCI symbol "ƒ" (which has a decimal value of 131), java does not complain by throwing an error that value 131 is out of range defined by byte (-128 and 127)? When I try to test this using literals I get two different results.
The following works:
byte b = 120;
int c = b;
System.out.println((char)c);
Output: x
But this does NOT work (even though it works when added to xanadu.txt):
byte b = 131;
int c = b;
System.out.println((char)c);
Output: error: incompatible types: possible lossy conversion from int to byte
byte b = 131;
I tried explicitly casting using byte: (how is this possible?)
byte b = (byte)131;
int c = b;
System.out.println((char)c);
Output: テ
I am total newbie when it comes to I/O streams, somebody please help me understand it.
EDIT: Turns out my knowledge on concepts of type casting was lacking, specifically in understanding the difference between "Widening" and "Narrowing". Reading up more about these concepts helped me understand why explicit (aka narrowing) casting works.
Allow me to explain: Look at the 3rd code block where I am explicitly casting the literal '131' to type of byte. If we are to convert the literal 131 into binary form of 32-bit signed 2's complement integer, we will get 00000000 00000000 00000000 10000011 which is 32-bits or 4 bytes. Recall that Java data type 'byte' can only hold 8-bit signed 2's complement integer, so, 131 is out of range and thus we get error "possible lossy conversion from int to byte". But, when we explicitly cast it to byte, we are 'chopping off' or correct term would be 'narrowing' the binary down to 8 bit integer. So, when we do that, then the resulting binary is 10000011 which is -125 in decimal value. Since -125 is in range of -128 and 127, byte has no issues accepting and storing it. Now when I try to story the value of byte in int c, implicit or "widening" casting takes place, where -125 in binary form of 8-bit 10000011 is converted into equivalent -125 in binary form of 32-bit 11111111 11111111 11111111 10000011. Finally, system.out is trying to output the value of (char)c which is another explicit or "narrowing" casting where its trying to shrink from 32-bit signed to 16-bit unsigned. When casting is complete, we get 11111111 10000011 in binary form. Now, when this binary is converted into character form by java, it returns テ.
I can conclude by saying that it helps converting everything into binary form and go from there. But make sure you understand encoding and 2's complement
I don't know where you got the value 131 from, but as far as I am concerned, LATIN SMALL LETTER F WITH HOOK (ƒ) is not in the original ASCII character set, but in extended ASCII, with a decimal value of 159. See here. It is also encoded in UTF-16 (how Java chars are encoded) as hex 192 (decimal value 402).
First, ensure that your text files are encoded in extended ASCII, and not UTF-8 (which is the most likely encoding). Then you can use a FileInputStream to read the file, and you will get 159.
Note that 159 is outside the range of the the Java byte type. This is fine, because read returns an int. If the text file is encoded in UTF-8 however, ƒ is encoded in 2 bytes, so read will be reading one byte at a time.
Your second code block doesn't work because as you said, byte goes from -128 to 127, so 131 obviously doesn't fit.
Your third code block forces 131 into a byte, which causes overflow and the value "wraps back around" to -125. b and c are both -125. When you cast this to a char it becomes 65411 because this conversion involves padding the whole number to 16-bits first, then treating it as an unsigned integer.
The reason why this all works when you use FileInputStream.read instead of doing these conversions yourself, is because read actually returns an int, not a byte. It's just that the int it returns will always be in the range -1 ~ 255. This is why we say "read returns a byte", but its actual return type is int.
byte b = 131; // this is 8 bits type, but >8 bits value
int c = b; // this is 32 bits type
System.out.println((char)c); // this is 16 bits type
Output: error: incompatible types: possible lossy conversion from int to byte
byte b = 131;
The two-complement encoding of 131 is:
2^7+2^1+2^0
^^^
sign bit
131 won't fit in a signed byte without an overflow in the two complement representation that is used for signed types. The highest bit=sign bit is set which gets extended when casting from byte to int.
The Java compiler notices that 131 won't fit properly in a byte which leads to the error.

Why is the result of Byte.parseByte recognised as an integer? [duplicate]

This question already has answers here:
Byte arithmetic: How to subtract to a byte variable? [duplicate]
(4 answers)
Closed 8 years ago.
I'm a beginner to Java, I'm fooling around with primitive numerical types, and when I parse String to Byte I can't work with the resulting byte variable (I'm squaring it), as error returned "is type mismatch: cannot convert from int to byte."
static byte squareByte(String p1){
//parse String to byte
byte result = Byte.parseByte(p1);
//return type byte
return result * result;
}
I've used "System.out.println( ((Object)result).getClass().getName());" to determine the variable type after parsing to byte, and it prints that it is byte, so why do I get an error regarding the result being an int?
I find I have to parseByte and then cast Byte just for the multiplication to work, can somebody explain why I have this problem with both Byte and Short, but not with any other primitive numerical type?
By default, the * operator returns int. If you want another type, like byte, you will have to do a cast, but there's a risk might overflow the type.
return (byte) (result * result);
Think of what will happen if the multiplication exceeds the value of 127, which is the byte limit?
When you perform any arithmetic operations (namely +,-,*,/ or %) with primitive types that are smaller than int, then the values are implicitly converted to an int before the arithmetic is done. This means that the result of byte * byte will be int rather than byte as you would expect.
You can see some further explanations and examples here
You can cast the result of the operation back to byte to make the code work, although you should think about what you want to happen if the result of the calculation will no longer fit into a byte (for example 12 will fit into a byte but 12 * 12 will not)
This happens because the JLS specifies that math operations like multiplication / addition etc must return an int
You have to use - return (byte) (result * result); to explicitly convert the integer result to byte.

How can i convert an integer to byte? [duplicate]

This question already has answers here:
Odd behavior when Java converts int to byte?
(12 answers)
Closed 9 years ago.
I want to know how can i convert an integer to byte theoretically.
I mean i don't want to use a predefined program but i want just to know how can i implement it.
What i know that from -128 to 127 an integer is the same as byte but the problemes is from 128 to 128 to +infinite and from -129 to -infinite.
For example given the following code:
Integer a = 140;//10001100 this is his binary conversion
Byte zz = (byte) a.byteValue();
System.out.println(zz);// result is -116
How that conversion works in java?
Thanks in advance
That value is out of range of the Byte and hence overflows.
Refer JLS 4.2.1:
The values of the integral types are integers in the following ranges:
For byte, from -128 to 127, inclusive
A byte is 8 bits , the most significant bit specifies the sign of the number and are are encoded in two's complement.
Read this wonderful SO answer for more.
when you are narrowing a primitive, you must explicitly make a cast - so you acknowledge a possible loss of data.
There is no loss if value is within the -128...127 byte value range
Byte value binary representation will not change, it will still be 10001100 but it will be interpreted differently, since byte is a signed type in two's complement representation http://en.wikipedia.org/wiki/Twos_complement and since bit 7 is set it means that now it's a negative number -116
You can not convert value grate than 127 into byte as it do not have place to store it. As 140 in binary is 10001100 it mean that you need a type that store at lest 8 bits. A byte store 8 bits but one of then is reserved for sign. So you can not fit it into it. You can use short witch store 16 bits (15 and 1 for sign).
The zero in different types expressed in binary;
byte b = 0b000_0000;
short s = 0b000_0000_0000_0000;
int i = 0b000_0000_0000_0000_0000_0000_0000_0000;
If you try to declare something like:
byte b = 0b1000_1100;
The compiler will tall you Type mismatch: cannot convert from int to byte.

'byte' type in Java [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Literal Syntax For byte[] arrays using Hex notation..?
I am trying to create a byte array of size '1' that holds the byte 0x0. In Java, can I just do something like this:
byte[] space = new byte[1];
space[0] = 0x0;
Will the hex value 0x0 be converted to its byte rep of 00000000 and store it in space[0]?
Will the hex value 0x0 be converted to its byte rep of 00000000 and store it in space[0]?
In your executing program, there is only one representation of the Java byte value zero - the 8 bit 2's complement representation of the integer zero - 8 zero bits.
It doesn't make any difference whether you express the number literal in your source code as 0 (decimal) or 00 (octal) or 0x0. They all mean exactly the same thing.
So - Yes, your code does what you expect.
A simpler one line version would be:
byte[] space = new byte[] {0};
or
byte[] space = {0};
or even
byte[] space = new byte[1];
(The last one relies on the fact that Java byte arrays are default initialized to all zeros.)
Will the hex value 0x0 be converted to its byte rep of 00000000 and store it in space[0]?
Sort of yes. Technically (i.e. according to the JLS) what happens is this:
0x0 becomes an int literal. (The specific syntax used for the integer literal is actually immaterial at this point ... so long as it is valid.)
The int literal is narrowed using an implicit primitive narrowing conversion to a byte value.
The byte value is used in the initialization of the array.
The implicit narrowing in step 2 is allowed because:
This is in an assignment context.
The value being assigned is a compile time constant expression of an integer type. (A literal is a compile time constant expression.)
The actual value being assigned is in the range of the type it is to be assigned to. (In this case, -128 to +127.)
In layman's terms, the compiler "knows" that there will never be any loss of information in the narrowing conversion.
Yes this will do exactly what you think it should do. Also see this related question.

Categories