Home > Mobile >  How to cast an object to a primitive value?
How to cast an object to a primitive value?

Time:10-23

Here is a literal class that allows one to get a value of a specified type:

public class Literal {

    private final String value;

    public Literal(String value) {
        this.value = value;
    }

    public <T> T getValue(Class<T> type) {
        if (type == Boolean.class || type == Boolean.TYPE) {
            return type.cast("true".equalsIgnoreCase(value));
        }
        throw new UnsupportedOperationException();
    }

}

It works fine for object types:

new Literal("true").getValue(Boolean.class);

But it throws the error for primitive types:

new Literal("true").getValue(Boolean.TYPE);
java.lang.ClassCastException: Cannot cast java.lang.Boolean to boolean

Is it possible to return a boolean value without the exception?

Or maybe I can transform a primitive type to a corresponding object type before calling the method? Is there a method to transform boolean type to java.lang.Boolean.class, int type to java.lang.Integer.class, ...? Something like this:

new Literal("true").getValue(toObjectType(Boolean.TYPE));

CodePudding user response:

Yes.. and no.

In basis what you say is a non-sequitur. Your question is: "How do I put this round green in this square hole" - concepts that don't even align.

"An object" cannot become a primitive value, and "an object" cannot be used where a primitive is required. This: Object o = 5; is illegal plain and simple.

Except.. it isn't. And the reason it isn't, is only because of syntax sugar. The compiler KNOWS it is illegal but assumes you MEANT to write Object o = Integer.valueOf(5); so, it just assumes you meant that and generates code accordingly. Just go compile that, run javap -c -v and lo! A call to integer.valueOf you never wrote.

You can do the same thing here: Write an 8-nested if/elseif:

if (type == boolean.class /* or Boolean.TYPE - same thing */) {
  return (T) "true".equals(value);
}

The type.cast part only buys you a runtime check, which is literally pointless as you already just did so with an if, thus, (T) foo is superior to type.cast(foo) here. Even though (T) thing produces a warning - ignore it, you know the warning is irrelevant. The heap corruption it is warning you about cannot happen / the type.cast wouldn't fix it.

In other words, get rid of type.cast(x) and make that (T) x and the error goes away (and a warning comes in trade; but that one you can @SuppressWarnings). The code will do what you want:

boolean v = new Literal("true").getValue(boolean.class);

But note that the system auto-boxes and auto-unboxes anyway. You can't stop that from happening unless you make a new method for it:

boolean v = new Literal("true").getBooleanValue();

Where you can implement getBooleanValue as return "true".equals(value); of course.

"I do not want the overhead of autoboxing" and "... you will be making 8 additional methods then" go hand in hand. It's why e.g. IntStream exists instead of just having a Stream<Integer>.

NB: The cast operator is used for 3 utterly unrelated things. 2 of those 3 are about assertions (is this thing type X already? If yes do nothing, if no, throw an exception / break the JVM, depending on which of the 2) - only one actually converts things, and it's primitive conversion: the thing in the () has to be a primitive type. You can't get that kind of cast here, that kind of cast fundamentally is not dynamic. Hence, no conversion can take place, hence, trying to 'cast an object to lower-case-b boolean' is an error. "cast" the operator cannot do that.

CodePudding user response:

rzwitserloot already explained quite well how and why you should adjust the casting and the difference between primitives and objects.

I just wanted to give you a small executable example on top of that. You could do something like the following:

public class Literal {
    private final String value;

    public Literal(String value) {
        this.value = value;
    }

    public <T> T getValue(Class<T> type) {
        if (type == Boolean.class || type == Boolean.TYPE) {
            return (T) new Boolean(this.value); // or Boolean.valueOf(this.value)
        } else if (type == boolean.class) {
            return (T) this.value;
        }
        // [add other type checks here, if you want]
        throw new UnsupportedOperationException();
    }

    public boolean getBooleanValue() {
        return new Boolean(this.value); // or Boolean.valueOf(this.value)
    }
    
    /** This method is just here for demo purpose */
    public static void main(String[] args) {
        // Use it like this
        Boolean obj = new Literal("true").getValue(Boolean.TYPE);
        Boolean obj2 = new Literal("FALSE").getValue(Boolean.TYPE);
        boolean primitive = new Literal("true").getValue(boolean.class);
        boolean primitive2 = new Literal("FALSE").getValue(boolean.class);
        System.out.println(obj); // true
        System.out.println(obj2); // false
        System.out.println(primitive); // true
        System.out.println(primitive2); // false
        
        // Or this
        boolean primitive3 = new Literal("true").getBooleanValue();
        System.out.println(primitive3); // true
    }
}
  •  Tags:  
  • java
  • Related