javacastingoverridingoverloadingsuppress-warnings

Casted override and overloading, will the java compiler create the necessary bytecode?


Assume the next scenario:

interface FloatObject<V> extends Function<Float, V> {
   V apply(Float floatObject);

   default FloatObject<Float, V> x_5() {
      return aFloatObject -> apply(aFloatObject * 5);
   }
}

Where the parent either overrides in function of it's own implementation:

class FloatPrimitive<V> implements FloatObject<V> {
   V apply(float floatPrimitive);

   @Override
   default V apply(Float aFloat) {
      return apply((float) aFloat);
   }
   @Override
   default FloatPrimitive<V> x_5() {
      return floatPrim -> apply(floatPrim * 5); //This will use the primitive version.
   }
}

OR lets the language figure out what to do with a casting... Granted... to the outer side of the function there will be no difference after all...

// everything else about the class remains the same except `x_5()`.
@Override
@SuppressWarnings("unchecked")
default FloatPrimitive<V> x_5() {
   return (FloatPrimitive<V>) super.x_5(); //What will this do?
}

When the suppressed version executes apply(float floatPrimitive) on the x_5() instantiation... will the value accepted (a float primitive) be turned into a Float object and then to a float primitive again? Or will it skip the Object and directly execute the entirety as primitive?

My guess is that the cast is a crude cast... this means that the primitive will be casted into an Object, then the Object will get multiplied by 5, and the returned Object will then get casted once again as a primitive.

Unless... the javac is doing a very good inference... idk...


Solution

  • I think the answer becomes clear when you go a little more into detail. In the case of

    class FloatPrimitive<V> implements FloatObject<V> {
       V apply(float floatPrimitive);
    
       @Override
       default V apply(Float aFloat) {
          return apply((float) aFloat);
       }
       @Override
       @SuppressWarnings("unchecked")
       default FloatPrimitive<V> x_5() {
          return (FloatPrimitive<V>) super.x_5();
       }
    }
    

    you will simply get a ClassCastException, as the lambda can't be cast.

    You could do

    class FloatPrimitive<V> implements FloatObject<V> {
       V apply(float floatPrimitive);
    
       @Override
       default V apply(Float aFloat) {
          return apply((float) aFloat);
       }
       @Override
       default FloatPrimitive<V> x_5() {
          FloatObject<V> superImpl = super.x_5();
          return superImpl::apply;
       }
    }
    

    but it's fairly clear that, since you're invoking super.x_5().apply(...), that apply method accepts a Float, and of course boxes and unboxes.