Подкласс не совпадает с подтипом. Вы можете создать подклассы, которые не являются подтипами. Чтобы понять, что такое подтип, давайте начнем объяснять, что такое тип.
Когда мы говорим, что число 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) было явно изменено без сохранения свойств родительского типа. Подумайте с точки зрения клиента ваших классов. Они могут получить набор целых чисел , где ожидается список целых чисел . Клиент может захотеть добавить значение и добавить его в список , даже если это значение уже существует в списке . Но она не получит такого поведения, если ценность существует. Большой сюрприз для нее!
Это классический пример неправильного использования наследства. Используйте композицию в этом случае.
(фрагмент из: правильно использовать наследование ).