简体   繁体   中英

Super class reference to a sub class object?

Give me a situation where we need to use the super class reference to a subclass object in Java.Please give me a real time example.

Thx

I know this is old but this cropped up on a project I've been working on recently (just a junior developer doing something unexpected - there was no actual reason for it!) and I think some of the answers have missed the point..

This has nothing to do with normal polymorphism; I think the question relates to the case where the code looks like this:

class A {
    B b; //odd reference here..
}
class B extends A {
}

Where the sub-class is used in the definition of the super-class. As far a I can tell there is no legitimate reason for coding something like this yourself, however the reason the language allows you to do this is that it's required for some of the core Java classes eg Object .

For example, although it doesn't store a reference to it, the code for Object creates and returns a String object in it's default toString method, however, String is a sub-class of Object .

It's interesting to note that although it's technically allowed, it doesn't make sense to have a superclass create a subclass instance in its constructor.

eg

class A {
    B b;
    A(){
        b = new B();
    }
}
class B extends A {
}

This will just crash due to the fact that it creates an infinite loop, since B's constructor is calling A's constructor, which is calling B's constructor etc..

To Take Full Advantage of polymorphism...You have to understand polymorphism fully for you to really appreciate this... You can actually achieve the same behavior using an Interface as appropriate, so they say...

abstract class Shape {

    abstract double getArea();

}

class Rectangle extends Shape{
    double h, w;

    public Rectangle(double h, double w){

        this.h = h;
        this.w = w;
    }

    public double getArea(){
        return h*w;
    }
}

class Circle extends Shape{
    double radius;

    public Circle(double radius){
        this.radius = radius;
    }

    public double getArea(){
        return Math.PI * Math.sqrt(radius);
    }
}

class Triangle extends Shape{
    double b, h;

    public Triangle(double b, double h){
        this.b = b;
        this.h = h;
    }

    public double getArea(){
        return (b*h)/2;
    }


}

public class ShapeT{
    public static void main(String args[]){

    //USAGE
    //Without polymorphism
    Triangle t = new Triangle(3, 2);
    Circle c = new Circle(3);
    Rectangle r = new Rectangle(2,3);

    System.out.println(t.getArea());
    System.out.println(c.getArea());
    System.out.println(r.getArea());

    //USAGE with Polymorphism

    Shape s[] = new Shape[3];
    s[0] = new Triangle(3, 2);
    s[1] = new Circle(3);;
    s[2] = new Rectangle(2,3);

    for(Shape shape:s){
        System.out.println(shape.getArea());
    }

    }
}

I hope I'm not wrong on this... just a thought!

That question doesn't seem quite right ... putting an explicit reference to a child-class in the parent-class seems like an intent to break the hierarchy and the library.

As soon as the parent-class starts to carry a reference to the child-class, the parent-class is dependant upon knowing it's descendants; that is bad.

Unless the question was misquoted here, I'd say your interviewer was talking through his hat.

Using this kind of assignment you can not call the overloaded method in the subclass which is not in super class.

  public class Reference {


    public static void main(String args[]){
        A a = new B();
        //B b = new A(); // You can not do this, compilation error
        a.msg(); // calls the subclass method
        ((B)a).msg("Custom Message"); // You have to type cast to call this
        System.out.println(a.getClass());
        if(a instanceof B){//true
            System.out.println("a is instance of B");
        }
        if(a instanceof A){//true
            System.out.println("a is instance of A also");
        }


    }
}

class A{
    public void msg(){
        System.out.println("Message from A");
    }
}

class B extends A{
    public void msg(){//override
        System.out.println("Message from B");
    }
    public void msg(String msg){//overload
        System.out.println(msg);
    }

}
class Person
String hairColor = "default_noColor";
-----------------------------
class German extends Person
String hairColor = "brown";
-----------------------------
class Scandinavian extends Person
String hairColor = "red";
-----------------------------
public static void main(String args[]) {
    Person p = new Person();
    German g = new German();
    Scandinavian s = new Scandinavian();
    sysout p.hairColor // prints default_noColor
    if (cond1) {
        p = g;
    }
    sysout p.hairColor // prints brown
    else if (cond2) {
        p = s;
    }
    sysout p.hairColor // prints red
}

now, if germans start having black hair, i recompile class German and the main() is totally agnostic of how the German has changed. The main method continues to work as if nothing ever happened and prints black.
Kindly excuse minimal grammar and syntax

Uh, any time? If you have something like a polymorphic linked list:

class Node {
   has 'next' => ( isa => 'Node' );
}

class TextNode extends Node {
   has 'text' => ( isa => 'Str' );
}

class ImageNode extends Node {
   has 'image' => ( isa => 'Image' );
}

Then you can do:

TextNode->new( 
    text => 'Here is my cat:', 
    next => ImageNode->new(
        image => 'nibbler.jpg',
        next  => undef,
    ),
);

Your specific situation involves Node holding a reference to TextNode or ImageNode, which is probably fine in Java:

 Node->new( next => TextNode->new ( ... ) )

Though I would make Node a role in languages with that feature... the idea is largely the same.

The Liskov substitution principle states that subclasses should behave exactly like their superclasses, so you can substitute a subclass anywhere the superclass is used.

Here's an important and most instructive example: java.lang.reflect.Array :

The Array class provides static methods to dynamically create and access Java arrays.

  • getLength(Object array)
    • Returns the length of the specified array object, as an int.
  • get(Object array, int index)
    • Returns the value of the indexed component in the specified array object.
  • set(Object array, int index, Object value)
    • Sets the value of the indexed component of the specified array object to the specified new value.

Arrays are passed around as Object , which is the superclass of all array types. It's necessary because we're doing reflection: we don't always know what the array type will be at compile time.

It's really rather odd because the type of situation where it might be useful (supplying a custom implementation of a singleton object for instance) has better alternatives to that; in particular the service loader mechanism.

And outside the world of globals in disguise you do tend to run into issues with circular references. (Consider that the super reference within your sub-class field points to the enclosing super instance which in turn is a reference from within the sub-class ...)

I think this can happen if the class and its subclass share child parent relationship of some sort and the child has a reference to its parent, something like this

public interface Node
{   
    String getName();

    int getValue();

    Container getParentContainer();
}

public interface Container extends Node
{   
    Set<Node> getChildren();
}

I would be interested to see how this can be designed in a better way to resolve this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM