Чем подтипы отличаются от используемых подклассов? - PullRequest
14 голосов
/ 16 августа 2011

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

Как отличить подтипы от подклассов?

Ответы [ 6 ]

14 голосов
/ 16 августа 2011

В Java создание подклассов является своего рода подтипом.

Существует несколько способов, которыми Java допускает подтипы:

  1. Когда class A extends B, A является подтипом B, потому что B b = new A(...); в порядке.
  2. Когда interface A extends B, A является подтипом B, потому что B b = new A() { ... } в порядке.
  3. Когда class A extends B, A[] является подтипом B[], потому что B[] b = new A[0] в порядке.
  4. Когда class A implements B, A является подтипом B, потому что B b = new A(...) в порядке.

Звучит так, будто вы хотите отличить одного от других. Ниже следует сделать это.

static boolean isSubclass(Class<?> a, Class<?> b) {
  return !b.isArray() && !b.isInterface() && b.isAssignableFrom(a);
}

Он не будет обрабатывать подтипы общих классов из-за стирания типов. Class экземпляры не несут параметров типа во время выполнения, поэтому нет способа отличить тип времени выполнения new ArrayList<String>() от new ArrayList<Integer>().

7 голосов
/ 08 августа 2013

Подкласс не совпадает с подтипом. Вы можете создать подклассы, которые не являются подтипами. Чтобы понять, что такое подтип, давайте начнем объяснять, что такое тип.

Когда мы говорим, что число 5 имеет тип integer, мы утверждаем, что 5 принадлежит множеству возможных значений (например, посмотрите возможные значения для примитивных типов Java). Мы также утверждаем, что существует допустимый набор методов, которые я могу выполнить для значения, такие как сложение и вычитание. И, наконец, мы заявляем, что есть набор свойств, которые всегда выполняются, например, если я добавлю значения 3 и 5, я получу 8 в результате.

Чтобы привести другой пример, подумайте об абстрактных типах данных, Набор целых чисел и Список целых чисел , значения, которые они могут содержать, ограничены целыми числами. Они оба поддерживают набор методов, таких как add (newValue) и size () . И оба они имеют разные свойства (инвариант класса), Sets не допускает дублирования, в то время как List разрешает дубликаты (конечно, есть другие свойства, которым они оба удовлетворяют).

Подтип также является типом, который имеет отношение к другому типу, называемому родительским типом (или супертипом). Подтип должен удовлетворять признакам (значениям, методам и свойствам) родительского типа. Отношение означает, что в любом контексте, где ожидается использование супертипа, его можно заменить на подтип, не влияя на поведение выполнения. Давайте посмотрим код, чтобы проиллюстрировать то, что я говорю. Предположим, я пишу Список целых чисел (на каком-то псевдо-языке):

class List {
  data = new Array();

  Integer size() {
    return data.length;
  }

  add(Integer anInteger) {
    data[data.length] = anInteger;
  }
}

Затем я пишу Набор целых чисел как подкласс Списка целых чисел :

class Set, inheriting from: List {
  add(Integer anInteger) {
    if (data.notContains(anInteger)) {
      super.add(anInteger);
    }
  }
}

Наш набор целых чисел класс является подклассом Список целых чисел , , но не является подтипом , поскольку он не удовлетворяет всем функциям Список класс. Значения и сигнатура методов выполняются, а свойства - нет. Поведение метода add (Integer) было явно изменено без сохранения свойств родительского типа. Подумайте с точки зрения клиента ваших классов. Они могут получить набор целых чисел , где ожидается список целых чисел . Клиент может захотеть добавить значение и добавить его в список , даже если это значение уже существует в списке . Но она не получит такого поведения, если ценность существует. Большой сюрприз для нее!

Это классический пример неправильного использования наследства. Используйте композицию в этом случае.

(фрагмент из: правильно использовать наследование ).

7 голосов
/ 16 августа 2011

Как правило, создание подклассов означает наследование атрибутов родителя.Подтип просто означает, что над подтипом могут выполняться операции над супертипом.Обратите внимание, что подклассы - это особый случай подтипов.

в Java, интерфейсы представляют структуру для описания поведения, которое может демонстрировать тип, что делает его естественным представлением для подтипирования.Подклассы проявляются в иерархии классов.

5 голосов
/ 16 августа 2011

На этот раз Википедия дает очень прямой ответ на вопрос:

http://en.wikipedia.org/wiki/Subtype_polymorphism

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

Короче говоря, субтипирование происходит, когда вы выводите интерфейс (сигнатуры методов / точки доступа / способы реагирования на внешний мир) издругое, тогда как создание подклассов происходит, когда вы наследуете реализацию (методы, атрибуты / внутреннее состояние и внутреннюю логику) класса от другого класса посредством наследования.

Эта терминология не часто используется таким образом, и тип обычно относится к тип данных .

1 голос
/ 16 августа 2011

В Java subtyping применяется к интерфейсам, но subclasses не применяется к интерфейсам.

0 голосов
/ 16 августа 2011

Я не думаю, что Java различает их?У вас есть только классы.

...