Не абстрактный метод в java должен содержать как минимум
Кроме обычных классов в Java есть абстрактные классы . Абстрактный класс похож на обычный класс. В абстрактном классе также можно определить поля и методы, но в то же время нельзя создать объект или экземпляр абстрактного класса. Абстрактные классы призваны предоставлять базовый функционал для классов-наследников. А производные классы уже реализуют этот функционал.
При определении абстрактных классов используется ключевое слово abstract :
public abstract class Human < private String name; public String getName() < return name; >>
Но главное отличие состоит в том, что мы не можем использовать конструктор абстрактного класса для создания его объекта. Например, следующим образом:
Human h = new Human();
Кроме обычных методов абстрактный класс может содержать абстрактные методы . Такие методы определяются с помощью ключевого слова abstract и не имеют никакой реализации:
public abstract void display();
Производный класс обязан переопределить и реализовать все абстрактные методы, которые имеются в базовом абстрактном классе. Также следует учитывать, что если класс имеет хотя бы один абстрактный метод, то данный класс должен быть определен как абстрактный.
Зачем нужны абстрактные классы? Допустим, мы делаем программу для обслуживания банковских операций и определяем в ней три класса: Person, который описывает человека, Employee, который описывает банковского служащего, и класс Client, который представляет клиента банка. Очевидно, что классы Employee и Client будут производными от класса Person, так как оба класса имеют некоторые общие поля и методы. И так как все объекты будут представлять либо сотрудника, либо клиента банка, то напрямую мы от класса Person создавать объекты не будем. Поэтому имеет смысл сделать его абстрактным.
public class Program < public static void main(String[] args) < Employee sam = new Employee("Sam", "Leman Brothers"); sam.display(); Client bob = new Client("Bob", "Leman Brothers"); bob.display(); >> abstract class Person < private String name; public String getName() < return name; >public Person(String name) < this.name=name; >public abstract void display(); > class Employee extends Person < private String bank; public Employee(String name, String company) < super(name); this.bank = company; >public void display() < System.out.printf("Employee Name: %s \t Bank: %s \n", super.getName(), bank); >> class Client extends Person < private String bank; public Client(String name, String company) < super(name); this.bank = company; >public void display() < System.out.printf("Client Name: %s \t Bank: %s \n", super.getName(), bank); >>
Другим хрестоматийным примером является система геометрических фигур. В реальности не существует геометрической фигуры как таковой. Есть круг, прямоугольник, квадрат, но просто фигуры нет. Однако же и круг, и прямоугольник имеют что-то общее и являются фигурами:
// абстрактный класс фигуры abstract class Figure < float x; // x-координата точки float y; // y-координата точки Figure(float x, float y)< this.x=x; this.y=y; >// абстрактный метод для получения периметра public abstract float getPerimeter(); // абстрактный метод для получения площади public abstract float getArea(); > // производный класс прямоугольника class Rectangle extends Figure < private float width; private float height; // конструктор с обращением к конструктору класса Figure Rectangle(float x, float y, float width, float height)< super(x,y); this.width = width; this.height = height; >public float getPerimeter() < return width * 2 + height * 2; >public float getArea() < return width * height; >>
Абстрактные классы и методы
Класс, содержащий абстрактные методы, называется абстрактным классом. Такие классы помечаются ключевым словом abstract.
Абстрактный метод не завершён. Он состоит только из объявления и не имеет тела:
abstract void yourMethod();
По сути, мы создаём шаблон метода. Например, можно создать абстрактный метод для вычисления площади фигуры в абстрактном классе Фигура. А все другие производные классы от главного класса могут уже реализовать свой код для готового метода. Ведь площадь у прямоугольника и треугольника вычисляется по разным алгоритмам и универсального метода не существует.
Если вы объявляете класс, производный от абстрактного класса, но хотите иметь возможность создания объектов нового типа, вам придётся предоставить определения для всех абстрактных методов базового класса. Если этого не сделать, производный класс тоже останется абстрактным, и компилятор заставит пометить новый класс ключевым словом abstract.
Можно создавать класс с ключевым словом abstract даже, если в нем не имеется ни одного абстрактного метода. Это бывает полезным в ситуациях, где в классе абстрактные методы просто не нужны, но необходимо запретить создание экземпляров этого класса.
В тоже время абстрактный класс не обязательно должен иметь только абстрактные методы. Напомню ещё раз, что если класс содержит хотя бы один абстрактный метод, то он обязан быть сам абстрактным.
Создавать объект на основе абстрактного класса нельзя.
// нельзя. даже не пытайтесь AbstractClass abstractClass = new AbstractClass();
Абстрактный класс не может содержать какие-либо объекты, а также абстрактные конструкторы и абстрактные статические методы. Любой подкласс абстрактного класса должен либо реализовать все абстрактные методы суперкласса, либо сам быть объявлен абстрактным. Короче, я сам запутался. Пойду лучше кота поглажу.
Я вернулся. Давайте напишем пример для абстрактного класса.
Допустим, мы хотим создать абстрактный класс СферическийКонь и не менее идиотский класс СферическийКоньВВакууме, наследующий от первого класса.
package ru.alexanderklimov.expresscourse; public abstract class SphericalHorse < // абстрактный метод ржать() abstract void neigh(); // абстрактный класс может содержать и обычный метод void gallop() < System.out.println("Куда прёшь?"); >> class SphericalHorseInVacuum extends SphericalHorse
Когда вы напишете такой код, то студия подчеркнёт второй класс красной волнистой линией и предложит реализовать обязательный метод, который определён в абстрактном классе.


Соглашаемся и дописываем в созданную заготовку свой код для метода.
@Override void neigh()
В главной активности напишем код для щелчка кнопки.
public void onClick(View view) < SphericalHorseInVacuum horse = new SphericalHorseInVacuum(); horse.neigh(); // на основе абстрактного метода horse.gallop(); // обычный метод >
Обратите внимание, что абстрактный класс может содержать не только абстрактные, но и обычные методы.
Раннее мы создавали класс Фигура, у которого был метод вычисления площади фигуры. Метод ничего не делал, так как невозможно вычислить площадь неизвестной фигуры. Поэтому, этот метод можно сделать абстрактным, а в классах, производных от Фигуры, переопределить данный метод.
// абстрактный класс Фигура abstract class Figure < double dim1; double dim2; Figure(double a, double b) < dim1 = a; dim2 = b; >// абстрактный метод для вычисления площади abstract double area(); > // Клас Треугольник class Triangle extends Figure < Triangle(double a, double b) < super(a, b); >// переопределяем метод double area() < return dim1 * dim2 / 2; >> // В активности public void onClick(View view) < // Figure figure = new Figure(10, 10); // так нельзя Triangle triangle = new Triangle(10, 8); Figure figure; // так можно, так как объект мы не создаем figure = triangle; mInfoTextView.append("Площадь равна " + figure.area()); >
Фигура — это абстрактное понятие и мы не можем создать универсальный метод для вычисления площади. Поэтому мы создаём другой класс Треугольник и пишем код, вычисляющий площадь треугольника (загляните в учебник геометрии). Также вы можете создать новый класс Прямоугольник и написать свой код для вычисления площади этой фигуры.
Вам вряд ли придётся часто создавать абстрактные классы для своих приложений, но встречаться с ними вы будете постоянно, например, классы AsyncTask, Service и др.
Кот — понятие тоже абстрактное. А вот ваш любимец Васька или Мурзик уже конкретный шерстяной засранец. По запросу «abstract cat» мне выдало такую картинку. Всегда интересовал вопрос, где художники берут такую травку? (это был абстрактный вопрос).
26. Java – Абстракция: абстрактный класс и метод, наследование абстрактного класса
Абстракция – это качество общения с идеями, а не с событиями. Например, в случае с e-mail, подробные детали о происходящем во время отправки e-mail, используемый протокол сервером e-mail – всё это скрыто от пользователя. Тем не менее, для отправки e-mail вам достаточно напечатать содержимое, адрес получателя и нажать «отправить».
Так и в объектно-ориентированном программировании: абстракция – это процесс скрытия деталей реализации от пользователя, предоставляя ему только функционал. Иными словами, пользователь будет владеть информацией о том, что объект делает, а не как он это делает.
В Java абстракция достигается с использованием абстрактных классов и интерфейсов.
Абстрактный класс
Класс, который во время объявления содержит в себе ключевое слово abstract, известен как абстрактный класс.
- Абстрактные классы в Java могут содержать или не содержать абстрактные методы, т.е. методы без тела (public void get();)
- Если класс имеет хотя бы один абстрактный метод, то класс должен быть объявлен абстрактным.
- Если класс объявлен абстрактным, его нельзя реализовать.
- Чтобы использовать абстрактный класс, вам нужно наследовать его из другого класса, обеспечить реализацию абстрактных методов в нём.
- Если вы наследуете абстрактный класс в Java, вам нужно обеспечить реализацию всех абстрактных методов в нём.
Пример
Эта глава показывает вам пример абстрактного класса. Чтобы создать абстрактный класс, просто используйте ключевое слово abstract перед ключевым словом class во время объявления класса.
/* File name : Employee.java */ public abstract class Employee < private String name; private String address; private int number; public Employee(String name, String address, int number) < System.out.println("Собираем данные о работнике"); this.name = name; this.address = address; this.number = number; >public double computePay() < System.out.println("Внутри Employee computePay"); return 0.0; >public void mailCheck() < System.out.println("Отправляем чек " + this.name + " " + this.address); >public String toString() < return name + " " + address + " " + number; >public String getName() < return name; >public String getAddress() < return address; >public void setAddress(String newAddress) < address = newAddress; >public int getNumber() < return number; >>
Вы можете наблюдать, что помимо абстрактных методов класс Employee такой же, как и обычный класс в Java. Класс теперь абстрактный, но он всё ещё имеет три поля, семь методов и один конструктор.
Теперь попробуйте создать экземпляр класса Employee следующим образом:
/* File name : AbstractDemo.java */ public class AbstractDemo < public static void main(String [] args) < /* Следующие действия неверны и выдадут ошибку */ Employee e = new Employee("Иванов И.И.", "Минск, Беларусь", 43); System.out.println("\n Вызываем mailCheck, используя ссылку Employee --"); e.mailCheck(); >>
При попытке компиляции вышеприведённого класса вы получите следующую ошибку:
Employee.java:46: Employee is abstract; cannot be instantiated Employee e = new Employee("Иванов И.И.", "Минск, Беларусь", 43); ^ 1 error
Наследование абстрактного класса
Рассмотрим наследоавние абстрактного класса в Java на примере. Вы можете наследовать класс Employee, как конкретный класс, следующим образом:
Пример
/* File name : Salary.java */ public class Salary extends Employee < private double salary; // Годовая заработная плата public Salary(String name, String address, int number, double salary) < super(name, address, number); setSalary(salary); >public void mailCheck() < System.out.println("Внутри mailCheck класса Salary "); System.out.println("Отправляем чек" + getName() + " с зарплатой " + salary); >public double getSalary() < return salary; >public void setSalary(double newSalary) < if(newSalary >= 0.0) < salary = newSalary; >> public double computePay() < System.out.println("Вычисляем заработную плату для " + getName()); return salary/52; >>
Здесь вы не можете создать экземпляр класса Employee, но вы можете создать экземпляр класса Salary, используя который вы сможете получить доступ ко всем трём полям и семи методам класса Employee, как в примере ниже.
/* File name : AbstractDemo.java */ public class AbstractDemo < public static void main(String [] args) < Salary s = new Salary ("Петров П.П.", "Москва, Россия", 3, 3600.00); Employee e = new Salary ("Смирнов О.И.", "Смоленск, Россия", 2, 2400.00); System.out.println("Вызываем mailCheck, используя ссылку Salary --"); s.mailCheck(); System.out.println("\n Вызываем mailCheck, используя ссылку Employee --"); e.mailCheck(); >>
После запуска программы будет выдан такой результат:
Собираем данные о работнике Собираем данные о работнике Вызываем mailCheck, используя ссылку Salary –– Внутри mailCheck класса Salary Отправляем чек Петров П.П. с зарплатой 3600.0 Вызываем mailCheck, используя ссылку Employee –– Внутри mailCheck класса Salary Отправляем чек Смирнов О.И. с зарплатой 2400.0
Абстрактный метод
Если вы хотите, чтобы класс содержал конкретный метод, но вы желаете, чтобы фактическая реализация этого метода определялась дочерними классами, вы можете объявить метод в родительском классе как абстрактный
- Ключевое слово abstract используется для объявления метода абстрактным.
- Вам нужно разместить ключевое слово abstract перед именем метода во время его объявления.
- Абстрактный метод в Java содержит сигнатуру метода, но не содержит тела метода.
- Вместо фигурных скобок у абстрактного метода будет точка с запятой (;) на конце.
Рассмотрим пример абстрактного метода в Java.
Пример
public abstract class Employee < private String name; private String address; private int number; public abstract double computePay(); // Остаток определения класса >
Объявление метода абстрактным ведёт к двум последствиям:
- Класс, содержащий его, должен быть объявлен абстрактным.
- Любой класс, наследующий текущий класс, должен либо переопределить абстрактный метод, либо объявить себя абстрактным.
Примечание. В конце концов, класс-потомок должен реализовать абстрактный метод, иначе у вас будет иерархия абстрактных классов, экземпляры которых нельзя будет создать.
Предположим, что класс Salary наследует класс Employee, тогда он должен реализовать метод computePay() , как показано ниже:
/* File name : Salary.java */ public class Salary extends Employee < private double salary; // Годовая заработная плата public double computePay() < System.out.println("Вычисляем заработную плату для " + getName()); return salary/52; >// Остаток определения класса >
Оглавление
- 1. Java – Самоучитель для начинающих
- 2. Java – Обзор языка
- 3. Java – Установка и настройка
- 4. Java – Синтаксис
- 5. Java – Классы и объекты
- 6. Java – Конструкторы
- 7. Java – Типы данных и литералы
- 8. Java – Типы переменных
- 9. Java – Модификаторы
- 10. Java – Операторы
- 11. Java – Циклы и операторы цикла
- 11.1. Java – Цикл while
- 11.2. Java – Цикл for
- 11.3. Java – Улучшенный цикл for
- 11.4. Java – Цикл do..while
- 11.5. Java – Оператор break
- 11.6. Java – Оператор continue
- 12. Java – Операторы принятия решений
- 12.1. Java – Оператор if
- 12.2. Java – Оператор if..else
- 12.3. Java – Вложенный оператор if
- 12.4. Java – Оператор switch..case
- 12.5. Java – Условный оператор (? 🙂
- 13. Java – Числа
- 13.1. Java – Методы byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()
- 13.2. Java – Метод compareTo()
- 13.3. Java – Метод equals()
- 13.4. Java – Метод valueOf()
- 13.5. Java – Метод toString()
- 13.6. Java – Метод parseInt()
- 13.7. Java – Метод Math.abs()
- 13.8. Java – Метод Math.ceil()
- 13.9. Java – Метод Math.floor()
- 13.10. Java – Метод Math.rint()
- 13.11. Java – Метод Math.round()
- 13.12. Java – Метод Math.min()
- 13.13. Java – Метод Math.max()
- 13.14. Java – Метод Math.exp()
- 13.15. Java – Метод Math.log()
- 13.16. Java – Метод Math.pow()
- 13.17. Java – Метод Math.sqrt()
- 13.18. Java – Метод Math.sin()
- 13.19. Java – Метод Math.cos()
- 13.20. Java – Метод Math.tan()
- 13.21. Java – Метод Math.asin()
- 13.22. Java – Метод Math.acos()
- 13.23. Java – Метод Math.atan()
- 13.24. Java – Метод Math.atan2()
- 13.25. Java – Метод Math.toDegrees()
- 13.26. Java – Метод Math.toRadians()
- 13.27. Java – Метод Math.random()
- 14. Java – Символы
- 14.1. Java – Метод Character.isLetter()
- 14.2. Java – Метод Character.isDigit()
- 14.3. Java – Метод Character.isWhitespace()
- 14.4. Java – Метод Character.isUpperCase()
- 14.5. Java – Метод Character.isLowerCase()
- 14.6. Java – Метод Character.toUpperCase()
- 14.7. Java – Метод Character.toLowerCase()
- 14.8. Java – Метод Character.toString()
- 15. Java – Строки
- 15.1. Java – Метод charAt()
- 15.2. Java – Метод compareTo()
- 15.3. Java – Метод compareToIgnoreCase()
- 15.4. Java – Метод concat()
- 15.5. Java – Метод contentEquals()
- 15.6. Java – Метод copyValueOf()
- 15.7. Java – Метод endsWith()
- 15.8. Java – Метод equals()
- 15.9. Java – Метод equalsIgnoreCase()
- 15.10. Java – Метод getBytes()
- 15.11. Java – Метод getChars()
- 15.12. Java – Метод hashCode()
- 15.13. Java – Метод indexOf()
- 15.14. Java – Метод intern()
- 15.15. Java – Метод lastIndexOf()
- 15.16. Java – Метод length()
- 15.17. Java – Метод matches()
- 15.18. Java – Метод regionMatches()
- 15.19. Java – Метод replace()
- 15.20. Java – Метод replaceAll()
- 15.21. Java – Метод replaceFirst()
- 15.22. Java – Метод split()
- 15.23. Java – Метод startsWith()
- 15.24. Java – Метод subSequence()
- 15.25. Java – Метод substring()
- 15.26. Java – Метод toCharArray()
- 15.27. Java – Метод toLowerCase()
- 15.28. Java – Метод toString()
- 15.29. Java – Метод toUpperCase()
- 15.30. Java – Метод trim()
- 15.31. Java – Метод valueOf()
- 15.32. Java – Классы StringBuilder и StringBuffer
- 15.32.1. Java – Метод append()
- 15.32.2. Java – Метод reverse()
- 15.32.3. Java – Метод delete()
- 15.32.4. Java – Метод insert()
- 15.32.5. Java – Метод replace()
- 16. Java – Массивы
- 17. Java – Дата и время
- 18. Java – Регулярные выражения
- 19. Java – Методы
- 20. Java – Потоки ввода/вывода, файлы и каталоги
- 20.1. Java – Класс ByteArrayInputStream
- 20.2. Java – Класс DataInputStream
- 20.3. Java – Класс ByteArrayOutputStream
- 20.4. Java – Класс DataOutputStream
- 20.5. Java – Класс File
- 20.6. Java – Класс FileReader
- 20.7. Java – Класс FileWriter
- 21. Java – Исключения
- 21.1. Java – Встроенные исключения
- 22. Java – Вложенные и внутренние классы
- 23. Java – Наследование
- 24. Java – Переопределение
- 25. Java – Полиморфизм
- 26. Java – Абстракция
- 27. Java – Инкапсуляция
- 28. Java – Интерфейсы
- 29. Java – Пакеты
- 30. Java – Структуры данных
- 30.1. Java – Интерфейс Enumeration
- 30.2. Java – Класс BitSet
- 30.3. Java – Класс Vector
- 30.4. Java – Класс Stack
- 30.5. Java – Класс Dictionary
- 30.6. Java – Класс Hashtable
- 30.7. Java – Класс Properties
- 31. Java – Коллекции
- 31.1. Java – Интерфейс Collection
- 31.2. Java – Интерфейс List
- 31.3. Java – Интерфейс Set
- 31.4. Java – Интерфейс SortedSet
- 31.5. Java – Интерфейс Map
- 31.6. Java – Интерфейс Map.Entry
- 31.7. Java – Интерфейс SortedMap
- 31.8. Java – Класс LinkedList
- 31.9. Java – Класс ArrayList
- 31.10. Java – Класс HashSet
- 31.11. Java – Класс LinkedHashSet
- 31.12. Java – Класс TreeSet
- 31.13. Java – Класс HashMap
- 31.14. Java – Класс TreeMap
- 31.15. Java – Класс WeakHashMap
- 31.16. Java – Класс LinkedHashMap
- 31.17. Java – Класс IdentityHashMap
- 31.18. Java – Алгоритмы Collection
- 31.19. Java – Iterator и ListIterator
- 31.20. Java – Comparator
- 32. Java – Дженерики
- 33. Java – Сериализация
- 34. Java – Сеть
- 34.1. Java – Обработка URL
- 35. Java – Отправка Email
- 36. Java – Многопоточность
- 36.1. Java – Синхронизация потоков
- 36.2. Java – Межпоточная связь
- 36.3. Java – Взаимная блокировка потоков
- 36.4. Java – Управление потоками
- 37. Java – Основы работы с апплетами
- 38. Java – Javadoc
Отличия абстрактного класса от интерфейса (abstract class and interface)
Абстрактный класс — это класс, у которого не реализован один или больше методов (некоторые языки требуют такие методы помечать специальными ключевыми словами).
Интерфейс — это абстрактный класс, у которого ни один метод не реализован, все они публичные и нет переменных класса.
Интерфейс нужен обычно когда описывается только интерфейс (тавтология). Например, один класс хочет дать другому возможность доступа к некоторым своим методам, но не хочет себя «раскрывать». Поэтому он просто реализует интерфейс.
Абстрактный класс нужен, когда нужно семейство классов, у которых есть много общего. Конечно, можно применить и интерфейс, но тогда нужно будет писать много идентичного кода.
В некоторых языках (С++) специального ключевого слова для обозначения интерфейсов нет.
Можно считать, что любой интерфейс — это уже абстрактный класс, но не наоборот.
Отслеживать
11.5k 8 8 золотых знаков 42 42 серебряных знака 69 69 бронзовых знаков
ответ дан 10 июл 2013 в 8:34
112k 6 6 золотых знаков 93 93 серебряных знака 159 159 бронзовых знаков
А где я писал о «pure virtual методах» ? Я писал о том, что у метода отсутствует реализация. А виртуальный он или нет — это детали реализации языка.
11 июл 2013 в 6:55
Проще сказать что интерфейс это частный случай абстрактного класса
2 дек 2015 в 5:10
В с++ можно наследоваться от произвольного количества абстрактных классов. Употребление слов наследует/реализует — просто соглашение.
31 мая 2016 в 19:00
Java и новый C# имеют несколько расширенные определения интерфейса по сравнению с вашим
22 сен 2017 в 11:17
К слову, для C#8+ Ваш ответ более неактуален ¯_(ツ)_/¯
24 июн 2019 в 14:14
tl;dr: Абстрактный класс — средство разработки классов на нижнем уровне, средство для повторного использования кода; интерфейс — средство выражения семантики класса. Таким образом, это совершенно разные, мало связанные между собой понятия.
Думайте об этом по-другому.
Абстрактный класс — это «заготовка» класса: реализовано большинство методов (включая внутренние), кроме нескольких. Эти несколько нереализованных методов вполне могут быть внутренними методами класса, они лишь уточняют детали имплементации. Абстрактный класс — средство для повторного использования кода, средство, чтобы указать, какой метод обязан быть перекрыт для завершения написания класса.
Интерфейс же — это своего рода контракт: интерфейсы используются в определениях чтобы указать, что объект, который будет использован на самом деле, должен реализовывать (для входных параметров) или будет гарантированно реализовывать (для выходных параметров) набор методов и (что намного важнее!) иметь определённую семантику. Интерфейс вполне может быть и пустым, тем не менее, имплементировать интерфейс означает поддерживать данную семантику.
Абстрактные классы идеологически схожи с шаблонами C++: и те, и другие являются заготовками классов, но шаблону для получения класса нужно специфицировать шаблонные типы, а абстрактному классу — абстрактные методы.
Интерфейсы идеологически схожи с заголовочными файлами C++: они раскрывают методы и скрывают конкретную реализацию.
Вопрос о том, является ли интерфейс или абстрактный класс собственно классом — техническая подробность реализации, зависящая от конкретного языка программирования. Например, в C++ интерфейсы отсутствуют вовсе, и их приходится эмулировать классами без данных. Абстрактный класс в C++ как таковой также отсутствует, но им можно считать любой класс с абстрактными методами. (Отсюда ограничение C++: как минимум 1 абстрактный метод в абстрактном классе.) Также в C++ можно (непрямо) инстанциировать абстрактный класс, вызвать абстрактный метод и (возможно) получить ошибку времени выполнения. В C# интерфейсы и абстрактные классы встроены в язык.
Пример (на C#, конкретный язык значения не имеет):
// общий код для всех животных abstract class АбстрактноеЖивотное < public int Возраст < get; protected set; >public int Вес < get; protected set; >public bool Спит < get; protected set; >public void ПодатьГолос() < if (!Спит && Возраст >ВозрастПрорезанияГолоса) РеализацияПодатьГолос(); > abstract protected void РеализацияПодатьГолос(); readonly protected int ВозрастПрорезанияГолоса; > class Собака : АбстрактноеЖивотное < override protected void РеализацияПодатьГолос() < Гав(); >public void Гав() < // реализация >public Собака() < ВозрастПрорезанияГолоса = 2; >> class Кошка : АбстрактноеЖивотное < override protected void РеализацияПодатьГолос() < Мяу(); >public void Мяу() < // реализация >public Кошка() < ВозрастПрорезанияГолоса = 1; >>
interface IЖивотное < int ИнвентарныйНомер < get; >> class Лев : ОбитательЗоопарка, IЖивотное < // . >class Зебра : ОбитательЗоопарка, IЖивотное < // . >class Сторож : ОбитательЗоопарка < >// . void Инвентаризация() < Listобитатели = // . foreach (var обитатель in обитатели) if (обитатель is IЖивотное) // отделяем животных от неживотных ДобавитьЖивотное((IЖивотное)обитатель); > void ДобавитьЖивотное(IЖивотное животное) // сюда сможет попасть только животное < .
Отслеживать
ответ дан 10 июл 2013 в 12:52
206k 28 28 золотых знаков 291 291 серебряный знак 526 526 бронзовых знаков
IЖивотное я думаю, даром инквизицию отменили. нельзя так код писать. уже хочется на русском - так на русском. Да и у автора был php.
10 июл 2013 в 13:23
@KoVadim: Была бы инквизиция, писал бы на латыни. Почему нельзя? Приведите хотя бы один довод. Это ж пример. А отличие интерфейса от абстрактного класса одно и то же что у PHP, что у C#. (Ну, кроме незначительных технических деталей.)
10 июл 2013 в 15:00
это легкий троллинг, что кто то путает 1с и шарп. а по существу - есть один довод - переключаться долго. Хорошо, у меня капсом, а у людей по две кнопки жать нужно или человек будет смотреть и не понимать, почему переменная класса Сторож не приводиться к типу Стopoж (это для особых любителей загадка)
10 июл 2013 в 17:44
смысл киррилических идентификаторов понимается, когда видишь код с китайскими и арабскими идентификаторами (не забываем, что китайский пишется справа на лево!). Вот рефакторинг такого кода срывает крышу намертво.
10 июл 2013 в 19:28
@VladD, не хочу обидеть, но ваши регулярные ответы аналогичного объема смахивают на графоманию. Читать их интересно, но весь их смысл можно передать куда меньшим количеством слов. Ответ @KoVadim и есть пример такого "рефакторинга" ваших ответов.
10 июл 2013 в 20:47
Мне кажется достаточно любопытным, что данный вопрос помечен тегом «ооп», но при этом во многих ответах явно просачиваются специфические аспекты конкретных языков программирования. Я же постараюсь дать ответ исходя из понятий ООП и лишь потом показать, почему вообще это различие появилось в некоторых языках программирования.
Абстрактные классы и интерфейсы имеют определенное отношение к наследованию, точнее к моделированию мира. С их помощью мы хотим выразить, что у определенной группы вещей в нашей системе есть что-то общее: некоторое общее поведение, которое отличает эту группу штуковин от всех остальных.
Допустим, для примера, мы хотим смоделировать кнопки в интерфейсе пользователя. Поскольку мы говорим об ООП, то мы выделим некоторый тип Кнопки с некоторым набором операций (которые определяют поведение) и скрытого состояния, на которое опирается поведение (да, скрытого состояния может и не быть). При этом мы можем выделить три вида операции:
- Конкретная фиксированная операция, которая должна быть абсолютно стабильно для всех типов кнопок.
- Конкретная операция с поведением по умолчанию (т.е. операция, чье поведение подходит для многих типов кнопок, но могут быть кнопки с другим поведением).
- Декларация операции без конкретной реализации (т.е. операция, чье поведение определить невозможно, поскольку на этом этапе не известно разумное поведение по умолчанию или же операции могут слишком сильно различаться у разных кнопок).
Другими словами, тип Кнопки может содержать невиртуальные методы (non-virtual methods), виртуальные методы (virtual methods) и абстрактные методы (abstract methods).
Наличие разных типов методов является очень важным инструментом моделирования и позволяет весьма точно выражать намерения проектировщика. Например, мы можем добавить невиртуальную операцию «Нажатия на кнопку», которая будет делегировать часть своей работы виртуальному (или абстрактному методу) «Обработать нажатие», но при этом всегда выполнять определенную часть работы (прозорливый читатель увидит в этом описании паттерн «Шаблонный метод»).
После того, как мы определили базовый тип, пришло время определить произвольные типы. И тут начинаются вопросы. Точнее, вопросов никаких не возникает, когда у типа есть лишь один непосредственный базовый тип или все базовые типы содержат лишь декларации операций. Не проблема, унаследовать «Кнопку меню» от «Кнопки» и переопределить метод «Нажать на кнопку». Но что, если наш тип «Кнопка меню» будет отнаследован от двух типов с одной и той же виртуальной операцией? Как переопределить лишь одну, а оставить другую? А как быть клиенту нового типа и различить, какую операцию вызвать? А что если у двух базовых типов есть поле с одним именем? А что если у одного базового типа метод «Нажать кнопку» реализован, а у другого – лишь описан в виде декларации?
Нет, все эти проблемы решаемы, и в С++, и Eiffel, и других языках программирования вы можете довольно гибко контролировать, что и как переопределять, что прятать, что выставлять наружу и как вызвать метод определенного базового типа. Но для авторов некоторых языков программирования подобная сложность показалась излишней, и они пошли на хитрость и отделили типы, которые содержат лишь декларации методов в отдельную категорию, и так появились интерфейсы.
Теперь будет легко провести разницу между тремя понятиями – интферфейса, абстрактного базового класса и конкретного базового класса.
- Интерфейс – описывает некоторое семейство типов и содержит лишь декларации операций (да, я осознанно пишу слово «декларация», а не использую слово «контракт», которое в ООП имеет вполне определенное значение).
- Абстрактный базовый класс описывает некоторое семейство типов, но помимо декларации операций может содержать реализации по умолчанию (виртуальные методы) и фиксированные операции (невиртуальные методы).
- Конкретный класс описывает некоторое семейство типов, которое готово для использования клиентами. Такой класс не может содержать декларации операций и все его операции должны быть либо фиксированными (невиртуальные методы) или содержать реализацию по умолчанию (виртуальные методы). Есть еще один подвид конкретных классов – запечатанный (sealed) класс – это разновидность конкретного класса отнаследоваться от которого невозможно, а значит он может содержать лишь конкретные операции.
Выделение интерфейсов в отдельную категорию полезно не только с точки зрения упрощения реализации языков программирования, но и для выделения разных подходов к моделированию. Так, например, наследование классов моделирует отношение «Является» («Кнопка меню» ЯВЛЯЕТСЯ «Кнопкой»), а базовые классы обычно содержат определенный функционал, тесно связанный с функционалом производного класса. Базовые классы не просто моделируют группу типов, но и позволяют использовать повторно существующий функционал.
Интерфейсы же, по своей природе обладают меньшей связностью (low coupling), поскольку не обладают конкретным поведением, которое может осложнить жизнь класса-наследника. Интерфейсы также могут моделировать отношение «Является» («Кнопка меню» ЯВЛЯЕТСЯ «IКнопкой»), но могут определять и менее жесткое отношение «Может выполнять роль» (CAN DO). Например, интерфейс IEquatable из BCL определяет «дополнительное» поведение, которое говорит о возможности типов сравнивать значения объектов.