Предполагая, что это полный вопрос новичка, вот что представляют собой абстрактные классы в Java:
Существует три основных типа классов в Java, интерфейсы , абстрактные классы и классы . Каждый из них добавляет что-то конкретное к фактическому определению класса;
- Интерфейс определяет методы, которые можно найти ( и должны реализовывать ) в классе. Вкратце, интерфейсы определяют поведение.
- Абстрактные классы реализуют некоторые функциональные возможности, а также определяют дополнительные абстрактные методы , которые должны быть реализованы расширяемыми классами. Использование абстрактных классов аналогично прямому наследованию классов.
- Классы - это просто классы, с которыми вы, скорее всего, уже знакомы.
Существует множество причин для использования любого из возможных типов классов, однако чаще всего в современном коде Java вы увидите множество интерфейсов и группу классов, реализующих эти интерфейсы.
Примеры: Класс
Рассмотрим следующий класс:
public class Cat {
public void speak() {
System.out.println("Meow!");
}
public void eat(Food f) {
System.out.println("Om nom nom, this "+f.getName()+" is delicious!");
}
}
Это очень простой класс, с которым знаком каждый Java-кодер, даже начинающий. Здесь нет ничего особенного. Однако с этим у вас есть проблема: что, если у вас есть Dog
, который в основном такой же, но он явно лает вместо мяукает?
Пример: абстрактный класс
Проблема "Cat
или Dog
" может быть решена с помощью наследования. Традиционно стандартное наследование выглядит так:
public class Animal {
public void eat(Food f) {
System.out.println("Om nom nom, this "+f.getName()+" is delicious!");
}
}
public class Cat extends Animal {
public void speak() {
System.out.println("Meow!");
}
}
public class Dog extends Animal {
public void speak() {
System.out.println("Bark! Bark!");
}
}
Однако здесь кроется проблема: чтобы на самом деле сделать мяуканье Cat
или Dog
, нужно иметь код, который проверяет, какое именно животное является животным, привести его к правильному типу и затем вызвать метод :
if (animal instanceof Dog) {
((Dog) animal).speak();
} else if (animal instanceof Cat) {
((Cat) animal).speak();
}
Как видите, такого рода код совершенно бессмысленен! Конечно, мы хотели бы просто иметь возможность звонить animal.speak()
напрямую, верно? И для этого у нас есть абстрактные классы! Заменив класс Animal
в приведенном выше примере на этот
public abstract class Animal {
public void eat(Food f) {
System.out.println("Om nom nom, this "+f.getName()+" is delicious!");
}
public abstract void speak();
}
Вы можете сделать Dog
лай и Cat
мяу, просто позвонив animal.speak()
! Отлично, не правда ли?
Обратите внимание, что вы также можете определить поведение по умолчанию от speak()
до Animal
, а затем просто переопределить этот метод в Cat
и Dog
, а иногда это даже имеет смысл больше, чем я только что показал здесь.
В любом случае, возникает другая проблема: что если ваш Dog
является Animal
, а также Pet
? Java допускает только одиночное наследование, чтобы избежать проблемы наследования алмазов , поэтому у вас не может быть другого суперкласса для них. Вы можете добавить его в качестве суперкласса для Animal
, но опять же, не все животные являются домашними животными - в моем пруду, конечно же, нет бегемота!
Пример: интерфейс
Так как только интерфейсы определяют поведение вместо фактически реализуют их ( и это на самом деле связанное ключевое слово! ), вы можете использовать интерфейсы для определения дополнительного поведения для вашего оригинальный класс. Предположим, что домашние животные, как правило, могут быть ухожены между прочим, поэтому интерфейс для Pet
будет выглядеть так:
public interface Pet {
void groom(Brush b);
}
Теперь просто добавьте implements Pet
к вашему Dog
, и теперь он может быть ужасным! Просто чтобы убедиться, что первая строка вашего Dog
класса должна выглядеть так:
public class Dog extends Animal implements Pet {
Теперь, чтобы ухаживать за Dog
или любым другим Pet
, вы можете сделать это:
if (animal instanceof Pet) ((Pet) animal).groom();
Вот и все. В качестве упражнения попробуйте реализовать Animal
в качестве интерфейса; обратите внимание, что интерфейсы могут фактически расширять другие интерфейсы.
PS. Также перечисления и анонимные внутренние классы могут рассматриваться как типы классов, однако они не совсем основные, которые каждый должен знать сразу после изучения основ Java.