Это все еще полиморфизм?

Во время кодирования у меня возникло интересное сомнение по поводу полиморфизма, и я не мог найти решения для этого.

public class Animal {
  public void getLegs() {
    SOP("4 legs"); 
  }
}

public class Kangaroo extends Animal {
  public void getLegs() {
    SOP("2 legs"); 
  }
  public static void main(String[] args) {
    Animal a = new Kangaroo(); // without changing this how can I get Animal getLegs
    SOP(a.getLegs()); // Important Line
  }
}

Теперь, если я хочу вызвать метод getLegs для Animal, как мне это сделать? Является ли это возможным? Это все еще полиморфизм?


person chaosguru    schedule 19.06.2012    source источник
comment
Вы не можете. В этом весь смысл полиморфизма. В Кенгуру вы можете сделать super.getLegs(), но не main.   -  person Amir Raminfar    schedule 19.06.2012
comment
comment
Весь смысл полиморфизма в том, чтобы получить доступ к наиболее специализированному методу.   -  person assylias    schedule 19.06.2012
comment
@Amir: А что, если мне нужно получить Animal getLegs(); ? super.getLegs () я всегда могу получить, но из экземпляра животного, разве это возможно?   -  person chaosguru    schedule 19.06.2012
comment
Нет, это невозможно из экземпляра. Это нарушает полиморфизм. Гарантируется только наличие метода getLegs. Но не то, как это реализовано. Как этому следовало быть. Почему вы хотите сделать это в любом случае?   -  person Amir Raminfar    schedule 19.06.2012
comment
@David Большое спасибо, это было полезно.   -  person chaosguru    schedule 19.06.2012
comment
@AmirRaminfar Разрешение людям вызывать реализацию из суперкласса для объекта не нарушит полиморфизм, поскольку вызов не будет задуман как полиморфный, но это серьезно нарушит инкапсуляцию, потому что тот факт, что базовый класс должен иметь реализацию getLegs, будет раскрыт во внешний мир.   -  person Sergey Kalinichenko    schedule 19.06.2012
comment
@chaosguru Если вы вызываете super.getLegs (), какой суперкласс? Этот код должен быть в подклассе, так как только подкласс имеет один суперкласс. Это хорошо, но зачем скрывать реализацию суперкласса за реализацией подкласса, который только явно вызывает суперкласс? Это может показаться умным, но на самом деле это просто программирование компьютера, чтобы он крутил пальцами. Вырезание кода будет иметь тот же эффект. Иногда super.getLegs() должен быть в подклассе, но только тогда, когда он изменяет значение суперкласса, как подкласс сиамских близнецов, возвращающий super.getLegs()*2   -  person Edwin Buck    schedule 19.06.2012
comment
@EdwinBuck: Да, ты прав! это звучит практично   -  person chaosguru    schedule 20.06.2012


Ответы (5)


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

Это работает следующим образом: только для статических методов вызывается метод, связанный с объявленным типом, а не с экземпляром объекта. Другими словами, он следует за классом, потому что метод является методом класса, а не методом экземпляра.

Пример взят с этой страницы:

public class Animal {
  public static void testClassMethod() {
      System.out.println("The class" + " method in Animal.");
  }
  public void testInstanceMethod() {
      System.out.println("The instance " + " method in Animal.");
  }
}

public class Kangaroo extends Animal {
  public static void testClassMethod() {
      System.out.println("The class method" + " in Kangaroo.");
  }
  public void testInstanceMethod() {
      System.out.println("The instance method" + " in Kangaroo.");
  }

  public static void main(String[] args) {
      Kangaroo myRoo = new Kangaroo();
      Animal myAnimal = myRoo;
      myRoo.testInstanceMethod();
      myAnimal.testInstanceMethod();
      Kangaroo.testClassMethod();
      Animal.testClassMethod();
  }
}

Результат будет таким (обратите внимание на 3-ю и 4-ю строки, а не на 1-ю и 2-ю):

The instance method in Kangaroo.
The instance method in Kangaroo.
The class method in Kangaroo.
The class method in Animal.
person Luca Geretti    schedule 19.06.2012

Да, это самая простая форма демонстрации полиморфизма.

По сути, вы имеете дело с Animal по имени a. Когда вы вызываете a.getLegs(), ваш код не привязывается к реализации getLegs() в Animal, а привязывается к самой низкой реализации подкласса, getLegs() в Kangraoo().

Если у Animal есть реализация, говорят, что она скрыта реализацией подкласса. Если Animal не имеет реализации, то невозможно создать автономные классы Animal, поскольку в них отсутствуют реализации для всех необходимых методов, и в таких обстоятельствах Animal называется абстрактным. класс (тот, который не может быть построен напрямую, а может быть создан только его подклассами).

person Edwin Buck    schedule 19.06.2012

В Java невозможно получить доступ к реализации Animal. Он всегда будет возвращать версию Кенгуру.

(Обратите внимание, что в C# это возможно, если пометить переопределяющий метод тегом "new", но это довольно специализированный вариант использования).

Доступ к тому, что выглядит как Animal, но получение поведения, указанного Kangaroo, — это именно то, что представляет собой полиморфизм — способность дочернего объекта подставляться туда, где ожидается его родитель.

Как правило, вы не хотели бы, чтобы вызывающий код знал об иерархии наследования, потому что это сильно связало бы ваш код вместе. Если вам действительно нужен доступ к реализации этого метода в Animal, это говорит о том, что ваш дизайн, вероятно, неверен.

person Paolo    schedule 19.06.2012

Суть полиморфизма в том, чтобы выполнять другой код, определяемый во время выполнения. Чтобы было понятнее, я немного изменю ваш код.

    public class Animal {

    public void getLegs(){
      SOP('4 legs'); 
     }

}
public class Kangaroo extends Animal{
 public void  getLegs(){
      SOP('2 legs'); 
  }
public static void main(String[] args){
  Animal a = new Kangaroo(); //without changing this how can I get Animal getLegs
  Kangaroo kng= new Kangaroo ();
  Animal an = new Animal();

  SOP(a.getLegs());  // Kangaroo's version is called
  SOP(kng.getLegs()); //Again, Kangaroo's version is called
  SOP(an.getLegs());   //Animal version is called

  }
}

и да, как все говорят, вы не можете вызывать Animal из своей строки Animal a = new Kangaroo();..так как никто не захочет этого делать. Скорее он будет прямо писать. Animal a = new Animal();..

Итак, наконец, объект, а не ссылка, решает, какой метод будет вызываться.

person Ahmad    schedule 19.06.2012

Теперь, если я хочу вызвать метод getLegs Animal, как мне это сделать? Является ли это возможным?

Если вы хотите получить доступ к переопределенному методу, который противоречит полиморфизму, вы можете использовать отражение. Получите метод getLegs из класса Animal, а затем вызовите его для своего объекта Kangaroo. Однако это хак, а не то, что вы делаете в обычной программе.

SOP( Animal.class.getMethod("getLegs").invoke(a) );
person eran    schedule 19.06.2012