How casting works in Java?
Does it converts
Object
reference type toProcessor
type which will be holding toObject
class Instance location?
No, because Object
does not implement the interface Processor
. Also because of this, the cast will fail, throwing a ClassCastException
.
Casting a type (Object
) to another unrelated type (Processor
) will generally fail.
What is happening actually?
Casting is you telling the compiler what type a variable should actually be, because you know better than than the compiler.
Here
Processor prcsr = (Processor) ob.getObject();
You are telling the compiler
Hey compiler, you only know that
obj.getObject
returns something of typeObject
, but I know better than you. I know thatobj.getObject
is going to return a type that implementsProcessor
.
The compiler hears this and goes "okay", and lets you assign it to the variable prcsr
, which is of type Processor
.
However, at runtime, it turns out that obj.getObject
returned an instance of Object
, which does not implement Processor
, so what you were telling the compiler was wrong, and an exception gets thrown.
Now let's say obj.getObject
actually returns an instance of FooProcessor
, which does implement Processor
(declaration not shown here):
Object getObject(){
return new FooProcessor();
}
Now at runtime, the cast succeeds because what you were telling the compiler was correct.
So basically, casting is mostly a compile time thing. Very little actually happens at runtime. At runtime it just checks whether what you were saying was right or not. If is wrong, throw an exception.
How does the Java cast operator work?
Is the JLS good enough?
Casting conversion is applied to the operand of a cast operator (§15.16): the type of the operand expression must be converted to the type explicitly named by the cast operator. Casting contexts allow the use of:
- an identity conversion (§5.1.1)
- a widening primitive conversion (§5.1.2)
- a narrowing primitive conversion (§5.1.3)
- a widening reference conversion (§5.1.5) optionally followed by an unchecked conversion (§5.1.9)
- a narrowing reference conversion (§5.1.6) optionally followed by an unchecked conversion
- a boxing conversion (§5.1.7)
- an unboxing conversion (§5.1.8).
Actually, maybe this part is more relevant:
The detailed rules for compile-time legality of a casting conversion of a value of compile-time reference type S to a compile-time reference type T are as follows:
- If
S is a class type:
- If T is
a class type, then either |S|
<: |T|, or |T| <:
|S|; otherwise a compile-time
error occurs. Furthermore, if there
exists a supertype X of
T, and a supertype Y of
S, such that both X and
Y are provably distinct
parameterized types (§4.5),
and that the erasures of X and
Y are the same, a compile-time
error occurs.
- If T is an interface type:
- If
S is not afinal
class (§8.1.1),
then, if there exists a supertype
X of T, and a supertype
Y of S, such that both
X and Y are provably
distinct parameterized types, and that
the erasures of X and Y
are the same, a compile-time error
occurs. Otherwise, the cast is always
legal at compile time (because even if
S does not implement T,
a subclass of S might).- If S is a
final
class (§8.1.1),
then S must implement T,
or a compile-time error occurs.
- If T
is a type variable, then this
algorithm is applied recursively,
using the upper bound of T in
place of T.- If T is
an array type, then S must be
the classObject
, or a
compile-time error occurs.- If S is
an interface type:
- If T is
an array type, then T must
implement S, or a compile-time
error occurs.
- If T is a type that is not
final
(§8.1.1),
then if there exists a supertype
X of T, and a supertype
Y of S, such that both
X and Y are provably
distinct parameterized types, and that
the erasures of X and Y
are the same, a compile-time error
occurs. Otherwise, the cast is always
legal at compile time (because even if
T does not implement S,
a subclass of T might).- If T is
a type that isfinal
,
then:
- If S is not a parameterized
type or a raw type, then T must
implement S, and the cast is
statically known to be correct, or a
compile-time error occurs.- Otherwise,
S is either a parameterized
type that is an invocation of some
generic type declaration G, or
a raw type corresponding to a generic
type declaration G. Then there
must exist a supertype X of
T, such that X is an
invocation of G, or a
compile-time error occurs.
Furthermore, if S and X
are provably distinct parameterized
types then a compile-time error
occurs.- If S is
a type variable, then this algorithm
is applied recursively, using the
upper bound of S in place of
S.- If
S is an array type SC[],
that is, an array of components of
type SC:
- If T is a
class type, then if T is not
Object
, then a
compile-time error occurs (because
Object
is the only class
type to which arrays can be assigned).
- If T
is an interface type, then a
compile-time error occurs unless
T is the type
java.io.Serializable
or
the typeCloneable
, the
only interfaces implemented by arrays.
- If T
is a type variable, then:
- If the upper
bound of T is
Object
or the type
java.io.Serializable
or
the typeCloneable
, or a
type variable that S could
legally be cast to by recursively
applying these rules, then the cast is
legal (though unchecked).- If the upper
bound of T is an array type
TC[], then a compile-time error
occurs unless the type SC[] can
be cast to TC[] by a recursive
application of these compile-time
rules for casting.- Otherwise, a
compile-time error occurs.- If T is
an array type TC[], that is, an
array of components of type TC,
then a compile-time error occurs
unless one of the following is true:- TC and SC are the
same primitive type.- TC and
SC are reference types and type
SC can be cast to TC by
a recursive application of these
compile-time rules for casting.
Perfectly clear now, isn't it? :D
In other words, this is the best I can do without knowing more details about your problem.
Java type casting. Logic behind (String), .toString() and + int
As was mentioned before, (String) myInt
is a typecast. In Java, we can either cast within primitives or upwards in the object-hierarchy. Since int
is a primitive and String
is an object, we have a problem. Even Autoboxing cannot resolve this dilemma since Integer
and String
do not stand in an inheritance-relationship. Therefore, it is perfectly plausible for (String) myInt
to result in a compilation error.
The semantics of Integer.toString(myInt)
and "" + myInt
are identical. The specifics, however, are different.
When executing Integer.toString(myInt)
, a new String
is constructed, containing a String-representation of myInt
.
When executing "" + myInt
, Java first constructs a global String
-constant, having the value ""
(this is done by the JVM, we do not see this 1). The lexer demands a String
on the right side of +
since it found a String
on the left side of +
. For primitives, the JVM "knows" how to convert them into String
s. For objects, toString()
is called. Since Object
has this method and each class is (at least implicitly) derived from Object
, each object is guaranteed to have a toString()
method. This is the second String
constructed. Since String
s are immutable, the JVM might create a third String
, representing the concatenation of the first two String
s2.
Epilogue
And then, at execution time, the JIT-compiler strikes and most of this might be irrelevant since the JIT-optimized versions of both variants may look equal. Or not. Or maybe only sometimes. JIT does funny stuff. So in the end it is more a question of personal style than performance :)
1 This is actually a lie. When writing
String s1 = "";
String s2 = "";
System.out.println(s1 == s2);
one will observe that the result is true
, whereas false
is expected. This is due to the fact that the JVM creates a pool for all String
constants to save some memory.
2 It is well possible that the JVM "recognizes" that something + "" == "" + something == something
and therefore does not create this third String
. I did neither test nor research this.
Java casting implementation
Could you please explain me how the casting works ( in memory )?
It works at byte code level not really in memory
How the variable type is changed on upcasting and downcasting?
If it is a primitive with an special bytecode instruction, for instance from long to integer as in:
long l = ...
int i = ( int ) l;
The bytecode is: l2i
if is a reference with the instruction checkcast
How the JVM knows that from this time it's safe to send this method to this object?
It doesn't, it tries to do it at runtime and if it fails throws an exception.
It is legal to write:
String s = ( String ) new Date();
Any type casting done by javac?
Actually, there are three possibilities in this case:
- The
javac
compiler could perform the optimization. - The JIT compiler could perform the optimization.
- The native code by the JIT compiler could include code to do a runtime type check.
I expect that it is option 1. or 2. but this could be platform specific.
In fact, on my system the bytecode is not optimized. If any optimization is to occur it will be up the the JIT compiler to do it. (This fits with what I've heard ... that most Java bytecode compilers do little in the way of optimization before generating bytecodes.)
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public Child getChild();
Code:
0: new #16; //class Child
3: dup
4: invokespecial #18; //Method Child."<init>":()V
7: astore_1
8: aload_1
9: checkcast #16; //class Child
12: areturn
}
Does using (Class) object reinstate the object in java?
It would be helpful if you provided more of a context as to what you are trying to achieve. I think what you have written now would throw a "Variable 'object' is already defined in the scope" error.
If you are trying to cast object to type Class, you would need to use a different variable name such as:
Class object2 = (Class) object;
This does not create or re-instantiate anything, the variable object2 still points to the same object.
For a more extensive answer on how casting is handled:
How does Java Object casting work behind the scene?
Performance of Object Typecasting
It is cheap enough that it falls into the category of premature optimization. Don't waste time even thinking or asking questions about it unless you have profiled your application and determined that it's a problem, and most importantly: don't compromise your design to avoid it.
Related Topics
Java Naming Convention with Acronyms
How Does the Jvm Ensure That System.Identityhashcode() Will Never Change
Can't Parse String to Localdate (Java 8)
Trouble with Gson Serializing an Arraylist of Pojo'S
Hashmap to Return Default Value for Non-Found Keys
How to Compile Multiple Java Source Files in Command Line
How to Read Text from Hidden Element with Selenium Webdriver
Java/Jaxb: Unmarshall Xml to Specific Subclass Based on an Attribute
How to Serialize Static Data Members of a Java Class
How to Decrypt an Encrypted Aes-256 String from Cryptojs Using Java
Differencebetween a Hashmap and a Treemap
Collection Interface VS Arrays
When Do You Need to Explicitly Call a Superclass Constructor
Fastest Way to Iterate an Array in Java: Loop Variable VS Enhanced for Statement
Javafx and Maven: Nullpointerexception: Location Is Required