Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How covariant method overriding is implemented using bridging Technique in java

While reading on Covariant Overriding, i find out very strange fact,

covariant method overriding is implemented using a bridging technique. it also said that this feature is implemented in java5 and above.(i think it is because generics introduced from java5)

How it happens.Please help me with example.

like image 543
Prateek Avatar asked Sep 06 '13 10:09

Prateek


People also ask

What is the covariant method overriding in Java?

The covariant method overriding approach, implemented in Java 5, helps to remove the client-side typecasting by enabling you to return a subtype of the overridden method's actual return type. Covariant Method overriding means that when overriding a method in the child class, the return type may vary.

How is covariant return types implemented?

How is Covariant return types implemented? Java doesn't allow the return type-based overloading, but JVM always allows return type-based overloading. JVM uses the full signature of a method for lookup/resolution. Full signature means it includes return type in addition to argument types.

What are covariant return types in Java why can we use them with overriding?

Covariant return type refers to return type of an overriding method. It allows to narrow down return type of an overridden method without any need to cast the type or check the return type. Covariant return type works only for non-primitive return types.

How does Java facilitate method overriding?

When a method in a subclass has the same name, same parameters or signature, and same return type(or sub-type) as a method in its super-class, then the method in the subclass is said to override the method in the super-class. Method overriding is one of the way by which java achieve Run Time Polymorphism.


2 Answers

Consider an example:

public interface Shape<T extends Shape<T>> {
    T getType();
    void setType(T type);
}

public class Circle implements Shape<Circle> {
    Circle getType() { }
    void setType(Circle circle) {  }
}

It looks good as of now. But, after type erasure, the interface loose it's generic type, and the type T is replaced with the upper bound. So the interface and class looks like:

public interface Shape {
    Shape getType();
    void setType(Shape type);
}

public class Circle implements Shape {
    Circle getType() { }
    void setType(Circle circle) {  }
}

Now, here's the problem. The method in Circle after erasure is not really an overridden version of Shape. Note that, now the methods as it looks, applies greater restriction on the parameter it takes, and the value it returns. This is because the erasure changes the signature of method in interface.

To solve this issue, the compiler adds bridge method for those, which delegates the call to those actual methods in class.

So, the class is really converted to:

public class Circle implements Shape {
    Circle getType() { }
    void setType(Circle circle) {  }

    // Bridge method added by compiler.
    Shape getType() { return getType(); }  // delegate to actual method
    void setType(Shape shape) { setType((Circle)shape); }  // delegate to actual method
}

So, the bridge method is now the overridden version of the methods in the interface, and they delegate the call to the actual method that does the task.

Note that the type used in the bridge method is the erasure of the type parameter of the interface, in this case Shape.


References:

  • Java Generics FAQs
    • What is a bridge method
    • Under what circumstances the bridge methods are generated?
like image 103
Rohit Jain Avatar answered Nov 15 '22 12:11

Rohit Jain


Given the following two classes:

public class Node<T> {
    private T data;
    public Node(T data) { this.data = data; }

    public void setData(T data) {
        System.out.println("Node.setData");
        this.data = data;
    }
}

public class MyNode extends Node<Integer> {
    public MyNode(Integer data) {
 super(data); }
    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

When compiling a class or interface that extends a parameterized class or implements a parameterized interface, the compiler may need to create a synthetic method, called a bridge method, as part of the type erasure process.

To solve this problem and preserve the polymorphism of generic types after type erasure, a Java compiler generates a bridge method to ensure that subtyping works as expected. For the MyNode class, the compiler generates the following bridge method for setData:

class MyNode extends Node {

    // Bridge method generated by the compiler
    //
    public void setData(Object data) {
        setData((Integer) data);
    }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }

    // ...
}
like image 36
Rakshit Jain Avatar answered Nov 15 '22 12:11

Rakshit Jain