88

I wonder if anyone could tell me how casting works? I understand when I should do it, but not really how it works. On primitive data types I understand partially but when it comes to casting objects I don't understand how it works.

How can a object with the type Object just suddenly be cast to, let's say, MyType (just an example) and then get all the methods?

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
user626912
  • 2,546
  • 3
  • 24
  • 33

5 Answers5

187

Casting in Java isn't magic, it's you telling the compiler that an Object of type A is actually of more specific type B, and thus gaining access to all the methods on B that you wouldn't have had otherwise. You're not performing any kind of magic or conversion when performing casting, you're essentially telling the compiler "trust me, I know what I'm doing and I can guarantee you that this Object at this line is actually an <Insert cast type here>." For example:

Object o = "str";
String str = (String)o;

The above is fine, not magic and all well. The object being stored in o is actually a string, and therefore we can cast to a string without any problems.

There's two ways this could go wrong. Firstly, if you're casting between two types in completely different inheritance hierarchies then the compiler will know you're being silly and stop you:

String o = "str";
Integer str = (Integer)o; //Compilation fails here

Secondly, if they're in the same hierarchy but still an invalid cast then a ClassCastException will be thrown at runtime:

Number o = new Integer(5);
Double n = (Double)o; //ClassCastException thrown here

This essentially means that you've violated the compiler's trust. You've told it you can guarantee the object is of a particular type, and it's not.

Why do you need casting? Well, to start with you only need it when going from a more general type to a more specific type. For instance, Integer inherits from Number, so if you want to store an Integer as a Number then that's ok (since all Integers are Numbers.) However, if you want to go the other way round you need a cast - not all Numbers are Integers (as well as Integer we have Double, Float, Byte, Long, etc.) And even if there's just one subclass in your project or the JDK, someone could easily create another and distribute that, so you've no guarantee even if you think it's a single, obvious choice!

Regarding use for casting, you still see the need for it in some libraries. Pre Java-5 it was used heavily in collections and various other classes, since all collections worked on adding objects and then casting the result that you got back out the collection. However, with the advent of generics much of the use for casting has gone away - it has been replaced by generics which provide a much safer alternative, without the potential for ClassCastExceptions (in fact if you use generics cleanly and it compiles with no warnings, you have a guarantee that you'll never get a ClassCastException.)

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
  • Thank you for your explanation. If I understand this correct, probably I don't, when you cast a object you are just telling the compiler that I know the object on this memoryadress know how to respond to these methods etc, so don't deny me? Is that correct? – user626912 Mar 13 '11 at 15:25
  • 1
    @user626912 Kind of - don't think about it in terms of memory addresses though. You're not just telling the compiler the given object conforms to an interface and therefore has implementations of given methods (you could create a totally different object with the same methods and casting wouldn't necessarily work.) You're telling the compiler that the object of one type is actually a more specific type, and therefore you can use the methods available on that more specific object. Have a read up on polymorphism if you haven't already, it might help to make some things clearer. – Michael Berry Mar 13 '11 at 17:25
  • I doubt your statement "you only need it when going from a more general type to a more specific type". ((Object) gpsLastLoc.getLatitude()).getClass().getSimpleName() will return the "double" name on the runtime, and this is the example usage of casting from more specific type to more general type. – 林果皞 Apr 15 '16 at 16:05
  • 1
    @林果皞 You're just using casting in this case to promote a primitive - this is not the same as going to a more general type, and a very odd way of doing things. The more normal (better) way would be `Double.valueOf(gpsLastLoc.getLatitude()).getClass().getSimpleName()`. In either case, you shouldn't ever need to get the class of a primitive dynamically, since if `getLatitude()` returns a double primitive, you always know it's going to promote to a `Double` object. – Michael Berry Apr 15 '16 at 16:37
  • @berry120 So, in this: `for (final Submodel submodel : submodels) { final NumericSubmodel numericSubmodel = (NumericSubmodel) submodel; ...}` the NumericSubmodel constructor will never be called, right? and it's additional fields (not present in Submodel) will not be set. – JonyD May 19 '17 at 12:44
  • @JonyD Correct, no action is performed on an object when you cast a variable that references it. – Michael Berry May 19 '17 at 16:20
  • Could you please tell my why do we cast it as (Integer) (Double)... rather than (int) (double) – F 505 Apr 25 '18 at 20:56
  • @F505 I was deliberately sticking to objects rather than primitives in the above example to avoid discussions around boxing / unboxing. You can of course cast to a primitive, just be aware that if you try to cast a null value to a primitive, you'll get a NPE thrown. – Michael Berry Aug 14 '18 at 11:34
7

Actually, casting doesn't always work. If the object is not an instanceof the class you're casting it to you will get a ClassCastException at runtime.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
sandrstar
  • 12,503
  • 8
  • 58
  • 65
5

Suppose you wanted to cast a String to a File (yes it does not make any sense), you cannot cast it directly because the File class is not a child and not a parent of the String class (and the compiler complains).

But you could cast your String to Object, because a String is an Object (Object is parent). Then you could cast this object to a File, because a File is an Object.

So all you operations are 'legal' from a typing point of view at compile time, but it does not mean that it will work at runtime !

File f = (File)(Object) "Stupid cast";

The compiler will allow this even if it does not make sense, but it will crash at runtime with this exception:

Exception in thread "main" java.lang.ClassCastException:
    java.lang.String cannot be cast to java.io.File
Bugs Happen
  • 2,169
  • 4
  • 33
  • 59
Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
3

Casting a reference will only work if it's an instanceof that type. You can't cast random references. Also, you need to read more on Casting Objects.

e.g.

String string = "String";

Object object = string; // Perfectly fine since String is an Object

String newString = (String)object; // This only works because the `reference` object is pointing to a valid String object.
asgs
  • 3,928
  • 6
  • 39
  • 54
3

The right way is this:

Integer i = Integer.class.cast(obj);

The method cast() is a much safer alternative to compile-time casting.

asgs
  • 3,928
  • 6
  • 39
  • 54
yegor256
  • 102,010
  • 123
  • 446
  • 597