1
class A {
    public void display(){
        System.out.println("From Class A");
    }
}

class B extends A {
    public void display() {
        System.out.println("From Class B");
    }
}

public class Test {
    public static void main(Strings[] args){

        A a = new A();
        A b = new B()
        a.display();
        b.display();
    }
}

Output:

From Class A    
From Class B

Now, I am getting the output as expected. But I want to know why I am using A b = new B(), when same thing I can achieve by using B b = new B().
What is the advantage of using former techniques, where and when it is beneficial for me?

Steve C
  • 18,876
  • 5
  • 34
  • 37
Ajay Yadav
  • 31
  • 1
  • 1
  • 7
  • 4
    See http://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface - not quite the question you asked, but you should find the answers enlightening. – Jon Skeet Sep 22 '16 at 13:13
  • Also take a look at this discussion: [Understanding “programming to an interface”](http://programmers.stackexchange.com/questions/232359/understanding-programming-to-an-interface). – DimaSan Sep 22 '16 at 13:18

2 Answers2

1

Lets take an example here. We all know birds can fly, but there are some exceptions. We know from their behavior, so lets model this.

Generally, birds can fly, so:

class Bird {
  void fly() {
      System.out.println("I can fly");
    }
 }

class Eagle extends Bird {
      void fly() {
        System.out.println("I can fly very high");
    }
}

We all know that ducks can't fly, but we don't say it for all birds. We say at runtime whether a specific bird can fly or not, depending on the bird.

class Duck extends Bird {
      void fly() {
        System.out.println("I can walk or swim only");
    }
}

class FlightDemo {
      public static void main(String[] args) {
         Bird bird = new Bird();
         bird.fly(); // output: I can fly

         Bird eagle = new Eagle();
         eagle.fly(); // output: I can fly very high

         Bird duck = new Duck();
         duck.fly(); // output: I can walk or swim only
      }
}

You saw that at runtime it's decided that ducks can't fly. You can override its fly behavior and it would walk or swim. We saw that Duck IS a Bird, and it can't fly, so we have overridden its behavior, and still Duck IS a Bird, and it can walk or swim.

iM71
  • 301
  • 2
  • 6
  • Irfan@ What is wrong in writing like: Duck duck = new Duck(); duck.fly(); will I not achieve the same functionality. – Ajay Yadav Sep 23 '16 at 05:19
  • There is nothing wrong, but that's not polymorphic. Bird decides at runtime which behavior it should assign, a duck or an eagle or just a bird. – iM71 Sep 23 '16 at 06:57
1

In your example, it doesn't matter which way you chose. Your example doesn't show the power of polymorphism.

Let's see a trivial example of Polymorphism:

enter image description here

interface Shape{
    void draw();
}

class Rectangle implements Shape{
    public void draw(){
        System.out.println("Drawing Rectangle.");
    }
}

class Triangle implements Shape{
    public void draw(){
        System.out.println("Drawing Triangle.");
    }
}

class Circle implements Shape{
    public void draw(){
        System.out.println("Drawing Circle.");
    }
}

Rectangle, Triangle, and Circle are just implementing their own definition of draw function.

Now, suppose you've to implement a drawAllShapes method in your Main class, which takes a bunch of shapes and print them all. But without polymorphism this can be hectic, as there can be different types of shapes. Now, here comes polymorphism to save us.

class RandomShapeFactory{
    public static Shape createRandomShape(){
        Shape randomShape;

        Random random = new Random();
        int randomNo = random.nextInt() % 3 + 1;
        if (randomNo == 1){
            randomShape = new Rectangle();
        }
        else if (randomNo == 2){
            randomShape = new Triangle();
        }
        else{
            randomShape = new Circle();
        }
        return randomShape;
    }
}

class Main{
    public static void main(String[] args){
        Shape[] shapes = new Shape[10];
        for (int i = 0; i < shapes.length; i++){
            shapes[i] = RandomShapeFactory.createRandomShape();
        }
        drawAllShapes(shapes);
    }

    public static void drawAllShapes(Shape[] shapes){
        for (int i = 0; i < shapes.length; i++){
            shapes[i].draw();
        }
    }
}

This implementation of drawAllShapes doesn't have to know whether the Shape at index i is a Circle or Triangle or what, whichever Shape it is, it just calls their implementation of the draw method.

main method has all random shapes, and when passed to the drawAllShapes method, their relative implementations are invoked.

This kind of implementation also follows the Open/Closed Principle, that if you want, in future, to add some more Shapes to the hierarchy, drawAllShapes method doesn't have to know about the new shapes either, just add new classes and implement the Shape interface, and drawAllShapes will work with those shapes too.

See the above example in action here.

Ahmad Khan
  • 2,655
  • 19
  • 25
  • Your answer is more towards software design principles and patterns instead of basic principle of run-time polymorphism. – Kahn Sep 23 '16 at 08:14
  • I think, the question was, why to use base class reference, and invoke the principle of run-time polymorphism instead of using the reference of the actual class itself. So I just tried to show the power of polymorphism with an example. – Ahmad Khan Sep 23 '16 at 08:43