0

I have this sample code/hierarchy to understand how compiler acts in this particular case.

I've the following classes/interfaces;

#1:

abstract class Vehicle<T extends Steering> {

   protected T mSteering;

   public Vehicle(T mSteering) {
       this.mSteering = mSteering;
   }

   void turnLeft() {
       mSteering.toLeft();
   }

   void turnRight(){
      mSteering.toRight();
   }
}

class Car<T extends Steering> extends Vehicle<T> {

    Car(T mSteering) {
        super(mSteering);
    }

    T getSteering(){
        return mSteering;
    }
}

#2:

interface Steering {
    void toRight();
    void toLeft();
}

class XSteering implements Steering {

    @Override
    public void toRight() {

    }

    @Override
    public void toLeft() {
        System.out.println("steering left by XSteering");
    }
}

public class YSteering implements Steering {

    @Override
    public void toRight() {

    }

    @Override
    public void toLeft() {
        System.out.println("steering left by YSteering");
    }
}

#3:

public static void main(String[] args) {

    Car c1 = new Car<>(new XSteering());
    c1.turnLeft();
    // XSteering steering1 = c1.getSteering(); // DOES NOT COMPILE

    Car c2 = new Car<>(new YSteering());
    c2.turnLeft();
}

The code outputs as expected;

steering left by XSteering
steering left by YSteering

So, when I remove the comments in the following line though;

XSteering steering1 = c1.getSteering();

It doesn't compile.

So, when type erasure takes place during compilation, I expect that the return type of the method is replaced with Steering getSteering() as it's the leftmost bound. This is OK. My question is more about what's happening on the call site. Since getSteering() has the generic return type I was also expecting the compiler adds the necessary cast in where you call the function so you wouldn't add an explicit cast to make it work (or in other words, compiler wouldn't give a complication error). Can someone where's my understanding fails in this case?

stdout
  • 2,471
  • 2
  • 31
  • 40

1 Answers1

2

You are using raw type here Car c1 = new Car<>(new XSteering()); That's why there is no type check and the compiler will not add any cast. T will be Steering since it is bound of T. Just use:

Car<XSteering> c1 = new Car<>(new XSteering());

See more What is a raw type and why shouldn't we use it?

Ruslan
  • 6,090
  • 1
  • 21
  • 36
  • 1
    Oh yes, I missed that point totally because the IDE did not give me any warnings then I thought it's "inferred" somehow. – stdout Mar 22 '19 at 11:50