To simplify some bytecode analysis, I want to replace explicit (down)casts of primitive types in a Java program by calls to the equivalent method of the boxed type. In most cases it's simple:
double d = 42.0;
int i = (int)d;
Can be turned into
Double tmp = new Double(d);
int i = tmp.intValue();
This works for all signed types. But there is not such methods for char
and Character
. That is, Integer, Float, etc have the methods intValue
, floatValue
, etc. but none has a method charValue
. Is there a jdk method to go from primitive type to char/Character?
So basically, is there something like this:
Integer num = new Integer(65);
char ch = num.charValue();
And the key is to not use (char)
.
If you're modifying bytecode, I think you do not need to cast to char
. In the bytecode, the char
type is a second-class citizen actually handled as an int
. From JVMS §4.9.2:
An instruction operating on values of type
int
is also permitted to operate on values of typeboolean
,byte
,char
, andshort
.As noted in §2.3.4 and §2.11.1, the Java Virtual Machine internally converts values of types
boolean
,byte
,short
, andchar
to typeint
.)
So while you can't, say, assign an int
to a char
in the Java language without an explicit cast, you can do that in the bytecode, since they have the same "verification type", which is int
. The bytecode representation of a char
is just an int
that happens to have its upper two bytes zero. So instead of:
char ch = num.charValue();
You would be able to get away with (in bytecode):
int ch = num.intValue() & 0x0000FFFF;
And then just pretend that ch
is a char
(e.g., pass it to methods that expect a char
or store it in a char
field or array).
However, if I understand it correctly, that's what the i2c
int
to char
cast instruction already does, so replacing it by an explicit AND operation is not going to be any simpler.
It's also surprisingly hard to find what actually happens if you cast a (signed)double into an (unsigned)char.
When you cast from float
or double
to byte
, short
, or char
, it first casts to int
, which saturates out-of-range values to Integer.MAX_VALUE
or Integer.MIN_VALUE
, and then truncates the bytes of the int
to fit the final type. See JLS §5.1.3 – Narrowing Primitive Conversion. The truncation step means that conversion of out-of-range floating-point values to byte
, short
, or char
is probably not going to give a useful result.