≡ Menu

Podcast Episode 20 – Casting

Podcast1Let’s kick off today’s podcast episode with a quick explanation of what ‘casting’ is in general.

Casting exists in today’s Object Oriented Programming languages, as it’s the means by which we turn one Object type into another Object type. Think of it like turning a caterpillar into a butterfly, only without that annoying cocoon stage.

In Java (and other object oriented programming languages) we can literally take an Object of one type and turn it into another type with just one line of code. I’ll get into what that code is in just a moment, but first I want to give you a little more background on casting.

What is Casting All About?

So in Java, casting is all about moving around the hierarchy of an Object. To explain this concept, I’ll use this as an example, picture the following hierarchy: Object -> Mammal -> Human. On the most generic end we have the Object, then we get a little bit more specific with the Mammal type, and then to the most specific type in our hierarchy the Human object.

Given this example, what do I mean by “moving around the hierarchy”? Well consider the most generic type in our example, the Object… what sort of operations can you perform on an Object? Can you ask the Object what it’s name is? No! It’s an Object, it only has a handful of operations that you can perform (namely, toString(), hashCode() and equals()). So do you see how asking an Object what it’s name is doesn’t really make sense? On the contrary, let’s look at the most specific type in our example, the Human. Does asking the Human what it’s name is make sense? Sure it does, I would assume all Humans would have a name.

So do you see how the type of Object you’re looking at in a particular hierarchy is important when you’re deciding what methods to invoke? So, where you are in a particular Object’s hierarchy will dictate what you can do.

So how does this apply to casting? Well, casting is what allows you to change the Object you have into a more specific type of Object with the goal of gaining access to those additional methods/properties that you want to use.

There are two types of casts that you can do:

  1. Upcast
  2. Downcast

Upcasting is the simpler of the two casting options, and this is because it’s always safe to upcast. Let’s think about this for a moment, if you’re given a Human object, would it make sense for you to upcast that to a Mammal type? Of course it would, because a Human is a Mammal! This should be bringing back thoughts of inheritance in your brain. Inheritance is all about the “is a” relationship. So since a Human is a Mammal, then we can easily cast a Human into a Mammal.

The side effect of this is that we will lose whatever functionality that was specific to the Human type. So if the Human type defined a “name” property, we will no longer be able to access that property. We will still be able to access all the methods and properties that are specific to the Mammal class though (like eyeColor for example). And then, since we’re still talking about Upcasting, you could upcast your Mammal variable to be of type Object if you like. Since a Mammal is an Object, the upcast makes perfect sense!

Alright, so that’s upcasting, pretty straight-forward. So now let’s talk about downcasting. This concept is just like an upcast, only in reverse. We are taking a more generic Object (like a Mammal) and trying to cast it down into a more specific type (like Human). So, all of the things I mentioned before about functionality still holds true here, only this time you will be gaining more functionality rather than losing it (as we’re getting more specific in our hierarchy).

What changes, is that downcasting can lead to errors if you’re not a bit careful. This goes back to my talk in inheritance about the direction that the inheritance flows. To refresh your memory I said that you could use the following exercise and ask yourself if “ALL” objects of one type would belong to another type. So in our example, we’d ask, “Are all Humans, Mammals?” vs “Are all Mammals, Humans?”. Well the answer is, “Yes all Humans are Mammals” and “No, not all Mammals are Humans”. So because of this, it’s safe to cast any Human into the category of Mammal, whereas it’s NOT safe to cast any Mammal into the category of Human! You see where I’m going with this?

So since not all Mammals are Humans, if we try to downcast a Mammal to a Human, we should be sure that the Object in question really is a Human, otherwise we’ll get a ClassCastException. Now there is a way to verify if your Object is indeed a Human before you try to cast it, but I’ll touch on that later.

Why Would we Cast an Object?

So all this talk about the implications of casting, but I haven’t yet explained WHY we would cast. There are a couple of reasons why one would need to perform a cast in Java.

  1. Casting to a more specific Object type to get access to additional functionality
  2. Casting to a different variable type in order to comply with the type restrictions on a method or constructor

The first reason we’ve already touched on, but let’s use a more common example than the Human/Mammal example. I’m sure at this point you’re familiar with what a Collection is, if not then I’d suggest you go back in the podcast history and listen to more shows… if you listened to that show already but just forget, I’ll jog your memory! A Collection is Java’s generic interface that is used to represent its data structures. Common Collections in Java are the List, Set or Map.

So let me give you another example of a type hierarchy: Collection -> List -> ArrayList. What would happen if you had a method defined that takes a generic Collection type, and within the method you want to use the functions of an ArrayList? Well, you wouldn’t be able to access all the methods in an ArrayList until you cast the variable from the generic Collection type to be an ArrayList (just like casting an Object to be a Human).

Fair enough, so what about the second reason for why we would cast an Object? Sometimes you need to comply with the types that are defined in certain methods. Normally, if a programmer is properly programming to an interface, then you should be safe with passing in your specific object type (as it will just upcast automatically for you)… but, there are some cases where a method will take a very specific parameter type, and you’ll need to cast your variable in order to comply with the method signature. An example of this would be if a method specifically needed an ArrayList, and the variable you want to pass in is declared as a (more generic) List type. This type of casting doesn’t happen often, but I’ve definitely encountered it before.

So HOW do you Cast Already!?

Okay so now that you’re familiar with the concept of casting, how do we actually accomplish it in code? Well it’s pretty simple really, all you need to do is figure out what variable type you want to cast to, and then include it in parenthesis before your variable.

So let’s talk about the List/ArrayList example. Let’s say you have two variables, one is called myArrayList, the other is called yourList. Let’s assume that myArrayList is defined as an ArrayList and yourList is defined as a List. You with me so far? Now let’s say that we want to assign myList to myArrayList, you could try to write:

  ArrayList myArrayList = new ArrayList();
  List myList = new ArrayList();

  // this will cause a compilation error
  myArrayList = myList;

But you will get a compilation error stating that you’ll need to cast myList to the ArrayList type. So to fix this, all you need to is add (ArrayList) before the myList variable, which indicates that you want to case myList to the ArrayList type.

The correct code would look like this:

  ArrayList myArrayList = new ArrayList();
  List myList = new ArrayList();

  // this will cause a compilation error
  myArrayList = (ArrayList)myList;

Quick Tip: If you are downcasting and you want to get access to the more specific methods/properties, just add another set of parenthesis around the variable and cast. For example ((ArrayList)myList).ensureCapacity(5), in this case, the ensureCapacity() method is not available for a List, just an ArrayList.

Type Checking Before Casting

If you want to do a bit of testing to ensure that a cast will work in code, you can use the instanceof keyword. So an example of this would be:

if (mammalVar instanceof Human)
{
  Human aHuman = (Human)mammalVar;
}

The if statement above will evaluate to true if the mammalVar is of type Human. So this is the kind of code you would use to ensure safe casting in Java.

Fun with Casting

One thing that you can try out yourself is trying to convert one primitives type into another primitive type. For example, what do you think happens when you have a double (which is a number with a decimal value) and try to cast the double to an int? Or vice-versa?

You’ll just have to try it out for yourself and see what happens!

{ 0 comments… add one }

Leave a Comment