1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-thinking-in-java-zh

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
7.1 向上转换.md 6.8 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 11.03.2025 09:15 d56454c

7.1 Вверх по иерархии

В главе 6 было показано, что объект можно использовать как своего типа или как экземпляр базового типа. Действие получения ссылки на объект и использование её как ссылки на базовый тип называется "вверх по иерархии" — так как диаграмма наследования обычно располагает базовые классы в верхней части.

Однако это также может привести к проблемам, как показано ниже (если возникают проблемы при выполнении этого примера, обратитесь к разделу Yöntem Atama" главы 3):

//: Music.java
// Наследование и вверх по иерархии
package c07;

class Note {
  private int value;
  private Note(int val) { value = val; }
  public static final Note
    middleC = new Note(0),
    cSharp = new Note(1),
    cFlat = new Note(2);
} // И т.д.

class Instrument {
  public void play(Note n) {
    System.out.println("Instrument.play()");
  }
}

// Объекты Wind являются инструментами,
// поскольку они имеют одинаковое API:
class Wind extends Instrument {
  // Переопределяем метод интерфейса:
  public void play(Note n) {
    System.out.println("Wind.play()");
  }
}

public class Music {
  public static void tune(Instrument i) {
    // ...
    i.play(Note.middleC);
  }

  public static void main(String[] args) {
    Wind flute = new Wind();
    tune(flute); // Вверх по иерархии
  }
} ///:~

Проблемы могут возникнуть, если метод play переопределен в производном классе и поведение метода будет зависеть от конкретной реализации.Здесь метод Music.tune() принимает ссылку на Instrument, а также на все производные от Instrument. Когда ссылка на Wind передаётся в tune(), нет необходимости преобразования. Это допустимо; интерфейс Instrument должен существовать в Wind, так как Wind наследуется от Instrument. Преобразование снизу вверх от Wind до Instrument может "сужать" этот интерфейс, но никогда не делает его меньше полного интерфейса Instrument.## 7.1.1 Почему нужен вверх по иерархии?

Этот пример может выглядеть странным. Почему всем следует забывать тип объекта? При использовании вверх по иерархии могут возникнуть такие вопросы. Кроме того, если бы tune() просто получал ссылку на Wind и использовал её как параметр, это могло бы быть проще и более очевидным. Однако важно отметить: если бы это было сделано, потребовалось бы создание нового метода tune() для каждого типа Instrument внутри системы. Предположим, что мы добавили два новых типа Instrument: Stringed (строе) и Brass (медные):

//: Music2.java
// Переопределение вместо приведения типов

class Note2 {
  private int value;
  private Note2(int val) { value = val; }
  public static final Note2
    middleC = new Note2( Yöntem2(0)),
    cSharp = new Note2( Yöntem2(1)),
    cFlat = new Note2( Yöntem2(2));
} // И так далее.

class Instrument2 {
  public void play(Note2 n) {
    System.out.println("Instrument2.play()");
  }
}

class Wind2 extends Instrument2 {
  public void play(Note2 n) {
    System.out.println("Wind2.play()");
  }
}

class Stringed2 extends Instrument2 {
  public void play(Note2 n) {
    System.out.println("Stringed2.play()");
  }
}

class Brass2 extends Instrument2 {
  public void play(Note2 n) {
    System.out.println("Brass2.play()");
  }
}

public class Music2 {
  public static void tune(Wind2 i) {
    i.play(Note2.middleC);
  }
  public static void tune(Stringed2 i) {
    i.play(Note2.middleC);
  }
  public static void tune(Brass2 i) {
    i.play(Note2.middleC);
  }
  public static void main(String[] args) {
    Wind2 flute = new Wind2();
    Stringed2 violin = new Stringed2();
    Brass2 frenchHorn = new Brass2();
    tune(flute); // Без приведения типов
    tune(violin);
    tune(frenchHorn);
  }
} ///:~
```Конечно, это работает, но существует существенный недостаток: требуется написание методов, связанных с каждым новым классом `Instrument2`. Это означает, что в первый раз потребуется гораздо больше кода. В будущем, если вы хотите добавить новый метод, такой как `tune()`, или новый тип для `Instrument`, вам всё равно придётся писать много кода. Кроме того, даже если вы забудете переопределить какой-либо метод, компилятор не сообщит вам об этом. Таким образом, управление всеми этими типами становится очень сложной задачей, которая может легко выйти из-под контроля.Но что, если бы мы просто написали один метод, используя базовый класс в качестве аргумента, а не специфические производные классы? То есть, если бы мы могли игнорировать производные классы и работать только с базовым классом, количество необходимого кода значительно уменьшилось бы.

Это именно то место, где "полиморфизм" проявляет свою мощь. Однако большинство программистов (особенно те, кто имеет опыт процедурного программирования) всё ещё чувствуют себя несколько неловко при работе с полиморфизмом.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-thinking-in-java-zh.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-thinking-in-java-zh.git
oschina-mirror
wizardforcel-thinking-in-java-zh
wizardforcel-thinking-in-java-zh
master