/ CASTING, API

Dynamic casting in Java

I’m a big fan of Baeldung’s blog. One of his latest post is about casting in Java. Unfortunately, I feel it misses one important point: dynamic casting. Since that’s is (very) relatively new, this post will try to fill that gap.

Do not use casting

The first thing is that it should be relatively easy to avoid casting.

Using polymorphism

Polymorphism is a great way not to cast. Consider the following code:

List animals = new ArrayList();
animals.add(new Cat());
animals.add(new Dog());
for (Animal animal: animals) {
    if (animal instanceof Cat) {
        ((Cat) animal).mew();
    } else if (animal instanceof Dog) {
        ((Dog) animal).bark();
    } else if (animal instanceof Snake) {
        ((Snake) animal).hiss();
    }
}

If all object types in the collection inherit from a single type, it’s possible to use polymorphism. Just add one method in this single type and override it in the subtypes.

public abstract class Animal {
    public abstract void makeSound();
}

public class Dog {
    @Override public void makeSound() {
        bark();
    }
}

public class Cat {
    @Override public void makeSound() {
        mew();
    }
}

Using generics

Polymorphism cannot be always applied. For example, this is the case when:

  • Items are not instances of related type
  • The parent type is not within our control sphere
  • etc.

In those cases, generics is another way to avoid casting.

Before Java 5, the following code would be the norm:

List dates = new ArrayList();
dates.add(new Date());
Object object = dates.get(0);
Date date = (Date) object; (1)
1 Casting required. Though the runtime type is Date, the compiler has no way to know about it.

With generics, the above code can be rewritten:

List<Date> dates = new ArrayList<>();
dates.add(new Date());
Date date = dates.get(0); (1)
1 No casting: the compiler has enough information thanks to generics.

When casting is mandatory

Despite to what some fanatics think, it happens that sometimes casting cannot be ignored.

One such use-case is the Servlet API. Map storing objects in servlet context/request/session do not use generics. And even if they did, they would be using Object.

// In a servlet
ServletContext context = getServletContext();
context.put("date", new Date());

// Somewhere else
ServletContext context = getServletContext();
Object object = context.get("date");
Date date = (Date) object;

Dynamic casting

The only form of casting originally available was static casting. Which means the casting type needs to be known at compile time. For example, let’s imagine a method that accepts a Stream<Object>, filters all element of a certain type and returns those elements in the right type. This is an example of the usage:

List<?> items = ...
List<Date> dates = filter(Date.class, items);

There’s no way to implement the filter method with static casting. There are actually two issues:

  1. The instanceof operator requires a type, not a Class instance e.g. item instanceof Date
  2. The cast syntax as well e.g. (Date) item

The instanceof operator can be replaced with a call to Class.isInstance(Object) (since JDK 1.1). This is quite well-known, if not widely used.

The API to replace the cast syntax, however, is much more "recent". There’s a Class.cast(Object) method since JDK 1.5 It is a simple wrapper around the legacy syntax.

Using both methods, it’s finally possible to implement the filter method above.

static <T> List<T> filter(Class<T> clazz, List<?> items) {
    return items.stream()
        .filter(clazz::isInstance)
        .map(clazz::cast)
        .collect(Collectors.toList());
}

Using the casting API allows dynamic casting. Without it, it’s not possible to implement the above method.

Conclusion

Despite what many people outside the ecosystem think, Java evolves, even if not very fast. However, developers needs to be acquainted with the new capabilities offered by each version.

Nicolas Fränkel

Nicolas Fränkel

Nicolas Fränkel is a technologist focusing on cloud-native technologies, DevOps, CI/CD pipelines, and system observability. His focus revolves around creating technical content, delivering talks, and engaging with developer communities to promote the adoption of modern software practices. With a strong background in software, he has worked extensively with the JVM, applying his expertise across various industries. In addition to his technical work, he is the author of several books and regularly shares insights through his blog and open-source contributions.

Read More
Dynamic casting in Java
Share this