Is there a form of "type safe" casting in Java?
Asked Answered
T

7

48

Suppose I have two classes deriving from a third abstract class:

public abstract class Parent{
    public Parent(){
    }
}

public class ChildA extends Parent {
    public ChildA {
    }
}

public class ChildB extends Parent {
    public ChildB {
    }
}

In C# I could handle casting in a somewhat type safe manner by doing:

ChildA child = obj as ChildA;

Which would make child == null if it wasn't a ChildA type object. If I were to do:

ChildA child = (ChildA)obj;

...in C# this would throw an exception if the type wasn't correct.

So basically, is there a way to to do the first type of casting in Java? Thanks.

Triangular answered 27/12, 2011 at 22:32 Comment(3)
Duplicate: #149328Clandestine
Apologies. I searched for "type safe casting java". Didn't occur to me to search for "as keyword java".Triangular
And then it blows up with an NPE. ;)Amply
R
76

I can't think of a way in the language itself, but you can easily emulate it like this:

ChildA child = (obj instanceof ChildA ? (ChildA)obj : null);
Richardricharda answered 27/12, 2011 at 22:35 Comment(2)
What about obj instanceof List<Integer> ? (List<Interger>)obj : null? You can not use instance of for a generic type, because it will disappear at runtime.Slashing
@Slashing You're right, you can't do that with a generic type if you also need to check for type of items. You could still do List ? (List)obj : null - but you'll get compile-time warnings. The question didn't say anything about generics.Richardricharda
B
28

In java 8 you can also use stream syntax with Optional:

    Object o = new Integer(1);

    Optional.ofNullable(o)
            .filter(Number.class::isInstance)
            .map(Number.class::cast)
            .ifPresent(n -> System.out.print("o is a number"));
Bouillabaisse answered 12/2, 2016 at 7:44 Comment(1)
Number.class::cast is f*** amazing! this one's great!Diagnostics
A
22

You can use this method which is compatible with all java types :

public static <T> T safeCast(Object o, Class<T> clazz) {
    return clazz != null && clazz.isInstance(o) ? clazz.cast(o) : null;
}

Example :

// A given object obj
Integer i = safeCast(obj, Integer.class);
Acrefoot answered 21/6, 2017 at 15:40 Comment(1)
And how do you get the class of, say, List<String> or Map<Integer,Object> ?Fimbriate
R
9

You can use the instanceof operator.

if(obj instanceof ChildA){
     final ChildA child = (ChildA) obj;
}
Razorbill answered 27/12, 2011 at 22:35 Comment(0)
D
6

In modern Java you would use

if (obj instanceof ChildA childa) {

}

which is nearly the same in modern C#

if (animal is Dog dog)
{
    // Use dog here
}
Disini answered 22/3, 2022 at 21:59 Comment(1)
And in this case, "modern Java" would be defined as Java 16.Frangos
V
3

I think a good way to deal with this is to use generic methods, which is a reusable/safe option as in the following example:

@SuppressWarnings("unchecked")
public <E> E coerceTo(Object o, Class<E> target) throws IllegalArgumentException {
  if(target.isInstance(o)) return (E)o;
  String msg = "expected "+target.getName()+" but was "+o.getClass().getName();
  throw new IllegalArgumentException(msg);
}

Note that here, the cast only occurs when safe, and it's correct to add the suppressWarnings annotation.

Here's an example of how to call the method:

 Object o = 1;
 int a = coerceTo(o, Integer.class);
Vernon answered 26/11, 2016 at 20:34 Comment(0)
P
2

You can always just check first:

if (child instanceof ChildA) {
    ChildA child = (ChildA) child;
    // Do stuff.
}

Or just make a quick method:

public ChildA getInstance(Parent p) {
    if (child instanceof ChildA) {
        return (ChildA) p;
    } else {
        return null;
    }
}
Pharisee answered 27/12, 2011 at 22:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.