Ссылка суперкласса на объект подкласса? - PullRequest
3 голосов
/ 29 марта 2010

Дайте мне ситуацию, когда нам нужно использовать ссылку на суперкласс для объекта подкласса в Java. Пожалуйста, дайте мне пример реального времени.

Thx

Ответы [ 9 ]

5 голосов
/ 13 апреля 2012

Я знаю, что это старый, но он возник в проекте, над которым я недавно работал (просто младший разработчик делал что-то неожиданное - не было реальной причины для этого!), И я думаю, что некоторые ответы пропустили точка ..

Это не имеет ничего общего с нормальным полиморфизмом; Я думаю, что вопрос относится к случаю, когда код выглядит так:

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

Где подкласс используется в определении суперкласса. Насколько я могу судить, нет законной причины для написания чего-то подобного самостоятельно, однако причина, по которой язык позволяет вам это делать, заключается в том, что это требуется для некоторых базовых классов Java, например. Object.

Например, хотя он не хранит ссылку на него, код для Object создает и возвращает объект String в методе по умолчанию toString, однако String является подклассом Object.

Интересно отметить, что хотя это технически разрешено, не имеет смысла заставлять суперкласс создавать экземпляр подкласса в его конструкторе.

, например

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

Это будет просто сбой из-за того, что он создает бесконечный цикл, так как конструктор B вызывает конструктор A, который вызывает конструктор B и т. Д.

2 голосов
/ 29 марта 2010

Этот вопрос кажется не совсем правильным ... размещение явной ссылки на дочерний класс в родительском классе кажется намерением нарушить иерархию и библиотеку.

Как только родительский класс начинает нести ссылку на дочерний класс, родительский класс зависит от знания его потомков; это плохо.

Если вопрос не был здесь неверно процитирован, я бы сказал, что ваш интервьюер разговаривал через шляпу.

2 голосов
/ 29 марта 2010

Чтобы воспользоваться всеми преимуществами полиморфизма ... Вы должны полностью понимать полиморфизм, чтобы по-настоящему оценить это ... Вы действительно можете добиться того же поведения, используя Interface в зависимости от обстоятельств, поэтому они говорят ...

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());
    }

    }
}

Надеюсь, я не ошибаюсь ... просто мысль!

1 голос
/ 30 декабря 2012

Используя этот вид назначения, вы не можете вызвать перегруженный метод в подклассе, который не входит в суперкласс.

  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);
    }

}
1 голос
/ 21 мая 2010
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
}

Теперь, если у немцев начнутся черные волосы, я перекомпилирую класс German, и main () совершенно не зависит от того, как изменился немец. Основной метод продолжает работать как ни в чем не бывало и печатает черным.
Извините, минимальная грамматика и синтаксис

0 голосов
/ 18 февраля 2015

Я думаю, что это может произойти, если у класса и его подкласса есть какие-то родственные родительские отношения, а у дочернего элемента есть ссылка на своего родителя, что-то вроде этого

public interface Node
{   
    String getName();

    int getValue();

    Container getParentContainer();
}

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

Мне было бы интересно посмотреть, как это можно сделать лучше, чтобы решить эту проблему.

0 голосов
/ 29 марта 2010

Это действительно довольно странно, потому что тип ситуации, в которой это может быть полезно (например, предоставление пользовательской реализации объекта-одиночки), имеет лучше альтернатив; в частности механизм загрузки сервиса.

И вне замаскированного мира глобалов вы склонны сталкиваться с проблемами с круговыми ссылками. (Учтите, что ссылка super в вашем поле подкласса указывает на включающий экземпляр super, который, в свою очередь, является ссылкой из подкласса ...)

0 голосов
/ 29 марта 2010

Вот важный и наиболее поучительный пример: java.lang.reflect.Array:

Класс Array предоставляет статические методы для динамического создания и доступа к массивам Java.

  • getLength(Object array)
    • Возвращает длину указанного объекта массива в виде целого числа.
  • get(Object array, int index)
    • Возвращает значение проиндексированного компонента в указанном объекте массива.
  • set(Object array, int index, Object value)
    • Устанавливает значение индексированного компонента указанного объекта массива в указанное новое значение.

Массивы передаются как Object, который является суперклассом всех типов массивов. Это необходимо, потому что мы размышляем: мы не всегда знаем, какой будет тип массива во время компиляции.

0 голосов
/ 29 марта 2010

Э, в любое время? Если у вас есть что-то вроде полиморфного связного списка:

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

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

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

Тогда вы можете сделать:

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

В вашей конкретной ситуации Node содержит ссылку на TextNode или ImageNode, что, вероятно, хорошо в Java:

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

Хотя я бы сделал Node ролью в языках с этой функцией ... идея в основном та же.

Принцип подстановки Лискова гласит, что подклассы должны вести себя точно так же, как и их суперклассы, поэтому вы можете заменить подкласс везде, где используется суперкласс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...