Что такое объект?
Java — это так называемый объектно-ориентированный (ОО) язык, при помощи которого вы можете заниматься объектно-ориентированным программированием (ООП). Такой стиль программирования очень отличается от процедурного программирования и может показаться немного странным для большинства программистов, не сталкивавшихся с ООП. Прежде всего, надо понять, что такое объект; именно на этом понятии базируется ООП.
Объект — это самостоятельный фрагмент кода, который знает о себе и может рассказать об этом другим объектам, если они зададут вопрос, который он понимает. Объект имеет члены (переменные) и методы, являющиеся вопросами, на которые он может ответить (даже если они не выглядят вопросами). Набор методов, на которые объект знает как реагировать, является его интерфейсом. Некоторые методы являются общедоступными (public), это означает, что другой объект может вызвать (или активизировать) их. Этот набор методов известен под названием public-интерфейс .
Когда один объект вызывает метод другого объекта, это называется передачей сообщения. Эта фраза соответствует ОО-терминологии, но чаще всего в Java-мире люди говорят «Вызвать этот метод», а не «Передать это сообщение». В следующем разделе мы рассмотрим концептуальный пример, который должен прояснить все это.
Концептуальный пример объекта
Предположим, что мы имеем объект Человек. Каждый объект Человек имеет имя, возраст, национальность и пол. Каждый объект Человек знает, как говорить и ходить. Один объект может спросить у другого о его возрасте, или может cказать, чтобы другой объект начал (или закончил) перемещение. В терминах программирования вы можете создать объект Person и назначить ему некоторые переменные (например, имя и возраст). Если вы создали второй объект Person, он может спросить у первого его возраст или сказать ему начать перемещение. Он может сделать это путем вызова методов первого объекта Person. Когда мы начнем писать код на языке Java, вы увидите, как язык реализует концепцию объекта.
Обычно концепция объекта остается неизменной и в языке Java и в других объектно-ориентированных языках программирования, хотя реализуют они ее по-разному. Эта концепция универсальна. По этой причине объектно-ориентированные программисты, независимо от применяемого ими языка, общаются не так, как процедурные программисты. Процедурные программисты часто говорят о функциях и модулях. Объектно-ориентированные программисты говорят об объектах и часто говорят о них, используя личные местоимения. Вы часто можете услышать, как один ОО-программист говорит другому: «Этот объект Supervisor говорит здесь объекту Employee «Дай мне свой ID», поскольку он должен назначить задания для Employee».
Процедурные программисты могут считать такой способ мышления странным, но он является естественным для ОО-программистов. В их программном мире все является объектом (с некоторыми исключениями в языке Java), а программы представляют собой взаимодействие (или разговор) объектов между собой.
Фундаментальные принципы ООП
Естественно, концепция объекта является критичным понятием для ООП, как идея о том, что объекты общаются между собой при помощи сообщений. Но существуют также три других фундаментальных принципа, которые вы должны понимать.
Вы можете запомнить три фундаментальных принципа ООП при помощи акронима PIE (ПНИ):
- Polymorphism (Полиморфизм)
- Inheritance (Наследование)
- Encapsulation (Инкапсуляция)
Это все необычные названия, но эти концепции не трудно понять. В следующих нескольких разделах мы подробно рассмотрим каждую из них в обратном порядке.
Инкапсуляция
Вспомните, что объект является самодостаточной сущностью, содержащей элементы данных и действия, которые он может выполнить с этими элементами. Это реализация принципа, известного под названием сокрытие информации. Идея заключается в следующем. Объект знает о себе. Если другой объект хочет узнать информацию о другом объекте, он должен спросить о ней. В терминах ООП он должен послать сообщение объекту, например, для запроса информации о его возрасте. В терминах Java он должен вызвать метод объекта, который возвращает возраст.
Инкапсуляция гарантирует индивидуальность каждого объекта, а программы представляют собой общение между объектами. Язык программирования Java позволяет программисту нарушить этот принцип, но это почти всегда является плохой идеей.
Наследование
При вашем рождении, говоря с биологической точки зрения, вы являлись комбинацией ДНК ваших родителей. Вы не были точной копией ни одного из них, но были похожи на обоих. ОО использует для объектов этот же принцип. Представьте опять объект Человек. Вспомните, что каждый этот объект имеет национальность. Не все эти объекты имеют одинаковую национальность, но не являются ли они похожими? Конечно! Это не Лошади, или Шимпанзе, или Киты. Это объект Человек. Все объекты Человек имеют определенные общие признаки, отличающие их от животных других типов. Но они немного отличаются друг от друга. Похож ли Ребенок на Подростка? Нет. Они двигаются и говорят по-разному. Но Ребенок определенно является Человеком.
В терминах ООП Человек и Ребенок являются классами в одной иерархии и (вероятнее всего) Ребенок наследует характеристики и поведение от своего родителя. Мы говорим, что конкретный Ребенок имеет тип Человек, или что этот Ребенок наследуется из объекта Человек. Это не срабатывает в обратную сторону — Человек не обязательно Ребенок. Каждый объект Ребенок является экземпляром класса Ребенок, и когда мы создаем объект Ребенок, мы создаем его экземпляр. Представляйте класс как шаблон для экземпляров этого класса. Обычно то, что может делать объект, зависит от типа объекта или, другими словами, от того, экземпляром какого класса он является. И Ребенок, и Подросток имеют тип Человек, но один может работать, а другой нет.
В терминах Java Человек — это суперкласс классов Ребенок и Подросток, которые являются подклассами класса Человек. Еще одной концепцией, связанной с наследованием, является абстракция. Человек находится на более высоком уровне абстракции, чем Ребенок или Подросток. Оба они имеют тип Человек, но несколько отличаются. Все объекты Человек имеют некоторые общие свойства (например, имя и возраст). Вы можете создать экземпляр класса Человек? Нет. Вы имеете либо экземпляр класса Ребенок, либо класса Подросток. Человек, в терминах Java, является абстрактным классом. Вы не можете иметь прямой экземпляр класса Человек. Только Ребенок или Подросток, которые оба имеют тип Человек, являются реальными. Рассмотрение абстрактных классов выходит за рамки данного руководства, поэтому мы больше о них говорить не будем.
Теперь, подумайте, что значит для объекта Ребенок действие «говорить». Мы рассмотрим смысл этого в следующем разделе.
Полиморфизм
«Говорит» ли Ребенок также как Подросток? Конечно же, нет. Ребенок издает шум, который не всегда является распознаваемыми словами, которые используют объекты Подросток. Поэтому, когда я создаю экземпляр объекта Ребенок (высказывание «создать экземпляр Ребенка» означает то же самое — слово «объект» подразумевается) и указываю ему «говорить», он может ворковать или булькать. Ожидается, что Подросток будет более внятен.
В иерархии человечества мы имеем класс Человек на вершине иерархии и классы Ребенок и Подросток ниже, в качестве подклассов. Все объекты Человек могут говорить, поэтому объекты Ребенок и Подросток тоже могут, но делают это по-разному. Ребенок булькает и издает простейшие звуки. Подросток произносит слова. Вот что означает полиморфизм: объекты делают вещи по-разному.
В чем состоит (и в чем нет) объектно-ориентированность языка Java
Как мы увидим, язык Java позволяет создавать первоклассные объекты, но не все в языке является объектом. Это немного не так, как в некоторых других объектных языках, например Smalltalk. Smalltalk является чистым объектно-ориентированным языком, т.е. все в нем является объектом. Язык Java является смесью объектов и других сущностей, не являющихся объектами. Он также позволяет одному объекту знать внутренности другого, если вы, как программист, реализуете такую возможность. Это нарушает принцип инкапсуляции.
Однако язык программирования Java также предоставляет каждому программисту инструменты, необходимые для следования всем правилам ООП и создания очень хорошего объектно-ориентированного кода. Но это требует некоторой дисциплины. Язык не заставляет вас делать правильные вещи.
Хотя многие ярые сторонники объектно-ориентированного подхода справедливо спорят о том, является ли язык Java объектно-ориентированным или нет, это на самом деле не так уж и важно. Платформа Java появилась, чтобы остаться. Научитесь применять ООП с Java там, где это возможно, и оставьте аргументы о чистоте другим. Язык Java позволит вам писать понятные, относительно лаконичные и управляемые программы, которые достаточно хороши для большинства профессиональных ситуаций.