javacovariancecovariant

Question about covariant parameters in Java


I have this piece of code:

class X {
    int x = 1;
}

class Y extends X {
    int y = 2;
}

class Z extends Y {
    int z = 3;
}


class A {
    public Y metodo1(Y y) {
        System.out.println("Metodo1 de A");
        return new Y();
    }

    public Y metodo2(Y y) {
        System.out.println("Metodo2 de A");
        return new Y();
    }
}

class B extends A {
    public X metodo1(Y y) {
        System.out.println("Metodo1 de B");
        return new X();
    }

    public Z metodo2(Y y) {
        System.out.println("Metodo2 de B");
        return new Z();
    }

    public void metodo3() {
        System.out.println("Metodo3 de B");
    }
}

class C extends A{
    public Y metodo1(X x) {
        System.out.println("Metodo1 de C");
        return new Y();
    }

    public Y metodo2(Z z) {
        System.out.println("Metodo2 de C");
        return new Z();
    }

    public void metodo3() {
        System.out.println("Metodo3 de C");
    }
}

public class DynamicBinding {
    public static void main(String[] args) {
        A b = new B();
        A c = new C();
        C c1 = new C();

        X x1 = b.metodo1(new Y());
        X x2 = b.metodo2(new Y());
        b.metodo3();

        X x3 = c.metodo1(new X());
        X x4 = c.metodo2(new Z());
        c.metodo3();

        X x5 = c1.metodo1(new Y());
        X x6 = c1.metodo1(new X());
    }
}

I know there are some errors like the covariant return type in

public X metodo1(Y y) {
      System.out.println("Metodo1 de B");
      return new X();
} 

or that b.metodo3(); doesn't exist, but my question is about this:

X x5 = c1.metodo1(new Y());
X x6 = c1.metodo1(new X());

Eclipse doesn't show me any errors, but I think that they have covariant arguments and that is not allowed in Java. What am I missing? (maybe in X x5 = c1.metodo1(new Y()); it calls the metodo1 of A, but I don't understand the other one).

Thanks!


Solution

  • A method in a sub class is not allowed to break the contract in a super class, so lets assume you have

    Class SuperClass{
      ReturnType method(ParameterType p) {..}
    }
    

    then any SubClass must either override method with

    ReturnType method(ParameterType p) {..}
    

    or

    ReturnTypeSubclass method(ParameterType p) {..}
    

    This ensures that when the class is used, there's no issues with types. The contract isn't broken with covariant return types, because ReturnTypeSubClass is a ReturnType.


    If you implement method in SubClass like so:

    AnyType method(ParameterTypeSubClass p) {..}
    

    ..you're not overriding it. You're overloading it. Now there are two method in SubClass. One is inherited from SuperClass.

    Imagine if it was overriding it and someone used the class like so:

    Super s = new SubClass;
    s.method(new ParameterType());
    

    an error would be thrown, because the overriding method would not be able to take a ParameterType, and the contract would be broken.