简体   繁体   中英

“Double casting”

I'm currently tutoring a high school student in AP Java and she asked me a question about "double casting". I did not ever hear of this term before, but apparently her teacher expects her to know it for their upcoming final.

The example her teacher provided was if you wanted to cast an Integer into a String, you would have to do the following to not get a compiler error:

Integer i = new Integer(5);
String s = (String)(Object) i;

The question is: when would you want to do this in real life?

The teacher only provided examples which result in a run time error. Also, I never really knew there was a term for this, but it just seems like a bad idea to do it because there's only an error when the two types are incompatible.

Thanks!

Yeah, I'm pretty sure that's not a thing. There's no reason that double casting would ever be necessary - it's possible it might get rid of a compile warning about unsafe casting (in which case you're probably doing it wrong), but otherwise that's just not right.

I mean, there's auto toString calling eg println("" + i) , but even then you don't need to cast to an object first...

Edit : After reading Tom's answer I'm suddenly unsure about this answer - primitives and (particularly) generics can actually use this. I don't have the ability to test anything right now, but anyone reading this answer should definitely take a look at his (and probably upvote it).

I'm going to stick to the line that there are no (or at least extremely few and far between) good reasons to do this, however, and the provided example certainly has nothing to do with it.

Whilst "double casting" certainly isn't a common term and you shouldn't seem any sort of casting of references much, you ought to know what happens (a ClassCastException ).

For completeness, there are some cases where it wouldn't CCE:

  • If the value is actually null .
  • Stuff involving primitives. (er, Object to Integer to [unboxing] int , or int to [lossy] byte to [positive] char )
  • Change generic type arguments. List<String> to Object to List<Integer> .

It is true that double casting would under most circumstances cause a ClassCastException , there are a few special cases. As mentioned in other answers, it can be useful for dealing with primitives and generics, but it can also be used when the compiled class doesn't necessarily represent the runtime class. This is especially true when ASM bytecode class transformers are involved.

As an example, I will use the Mixin framework. The following code will be injected to the Foo class at runtime. I won't get into the specifics of how this works too much.

@Mixin(Foo.class)
public class MixinFoo {

    public Foo bar() {
        return (Foo) (Object) this;
    }
}

The compile-time type of this seems to be MixinFoo , but this method actually gets dynamically inserted, so during runtime, it would be Foo . The compiler doesn't know this; we would have to cast it to Foo , but that would also cause a compiler error.

Casting to Object first then to Foo (double casting) would remedy the compiler's issue. Just remember if the method doesn't get applied at runtime, this WILL result in a runtime error.

Of course, this is well beyond the skill level of intro Java.

Definitely, though this just avoids compiler errors, run time errors are bound to occur. Also if two classes are in an inheritance hierarchy, there is no need to downcast to the base class and again upcast.

Even in the above question, there is finally a need of an API method to convert the objects.

I've recently come across this problem and a use for it. I have an array of objects with 2 integer values and a string. When I come to unpack it I need to convert the integers to double to do some division.

The problem is that when I come to cast the integer values to double it errors because Java automatically detects it as Integer object not int primitive and you can't convert from Integer to double.

The solution is therefore to use (double)(int)value before doing the division.

So to summaries, if you're storing int's as objects and you want to convert it to a double for some division, java will automatically convert it to an Integer making the division not possible.

A real use case would be:

static class Y extends X<Date> {
//some code
}

List<Y> n = new ArrayList<>();

someMethod((List<X<Date>>)(List<?>) n);

where

void someMethod(List<X<Date>>){
//some code
}

Here's a simple real world example I ran into, where you need to help compiler understand it should autobox before casting:

class NumberConverter<F extends Number, T> {

    public T convertNumber(F value) {
        if (targetType.equals(Integer.class) || targetType.equals(int.class)) {
            return (T) (Object) value.intValue();
        }

        (..)
    }
}

You can't cast directly to T, but you can cast to Object, which causes the JVM to autobox it before casting it to Object. Then you can cast to T without problem.

Yes, when you need to deal with the intersection of erased generics and type tokens.

Let's say you want to have a generic function that is type-safe both at compile time and run time. So you declare it with a type token:

public static <T> T getT(
    ExampleDataSource exampleDataSource,
    String key,
    Class<T> typeToken) {

    // code goes here...
}

This works great as long as you only try to retrieve non-generic types from your data source. For example:

String string = getT(source, "some-string", String.class);
int integer = getT(source, "some-integer", Integer.class);
DateTime dateTime = getT(source, "some-datetime", DateTime.class);

But what happens if you want to get a List<String> out of your data source? Well, the syntax for that is a pretty ugly double-cast. It also requires the data source to be able to figure out the erased type on its own, since it's not present in the type token at run time, despite the cast:

List<String> listOfString = getT(
    source,
    "some-list-of-strings",
    (Class<List<String>>) (Class) List.class
);

Why Java won't allow casting List.class directly to the (fictional) type Class<List<String>> in a single step I couldn't tell you. I hope Java gets reified generic types at some point in the future. Then List<String>.class would be a valid type token, and you wouldn't need any cast, much less a weird double raw-to-fake-generic cast.

Maybe this question is logic? I mean, there is method that calculate something (working with Integers) and returns Object, and usage of method where result casting to String, generaly this metod can be overridden a few times, functionality like this was used before Java 1.5 Were you define Generic calss (but without Generics) and returns of each method is Object becasue there are a few childs and each can return own type, I do not know but can be answer, and double casting like this

public class Main {
    public static void main(String[] args) {

        AbstractToDO abstractToDO2 = new SomeToDoTwo();
        String result2 = (String) abstractToDO2.toDo(); // here is second, all is good

        System.out.println(result2);

        AbstractToDO abstractToDO1 = new SomeToDoOne();
        String result1 = (String) abstractToDO1.toDo(); // here is second, Runtime error

        System.out.println(result1);

    }

    Object onePlusOne(){

        return 1+1 +" ";
    }
}

interface AbstractToDO{
     Object toDo();
}

class SomeToDoOne implements AbstractToDO{
    @Override
    public Object toDo() {
        return (Object)(1+1); // here is first casting, // we can use without (Object) casting
    }
}class SomeToDoTwo implements AbstractToDO{
    @Override
    public Object toDo() {
        return (Object)"1+1"; // here is first casting, // we can use without (Object) casting
    }
}

Although double casting may seem redundent in a programmer's prospective, knowing at least how the syntax works may help you understand the underlying workings of Java.

For example:

Let's say an Animal is a superclass of a Dog class. And we know the Object class is the superclass of all classes.

Dog d = new Dog(); 
Object a = d;          //no errors occur

Here, d is implicitly casted as an Object object. Explicitly, it would be Object a = (Object)d;

What about here?

Dog d = new Dog(); 
Object a = (Animal)d;  //no errors occur

We are casting d as a Animal object, but the compiler is implicitly casting it as an Object object. Double casting.

Which one is d ultimately casted as?

Explicitly, it would be Object a = (Object)(Animal)d;

Knowing the syntax of double casting, we would know d would ultimately be casted as an Object , hence no errors occur.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM