# Синтаксис создания классов

## Базовые сведения об объектах и классах

**Объектно-ориентированное программирование** – это методология программирования, основанная на представлении программы в виде совокупности взаимодействующих **объектов**, каждый из которых является экземпляром определенного **класса**, а классы являются членами определенной иерархии **наследования**.

**Объект** – структура, которая объединяет данные и методы, которые эти данные обрабатывают. Фактически, объект является основным строительным блоком объектно-ориентированных программ.

{% hint style="info" %}
Об объектах можно думать как о полезных существах, которые "живут" в нашей программе и коллективно решают некоторую задачу. Наша обязанность заключается в том, чтобы создать эти существа, распределить между ними обязанности, регламентировать сценарий их поведения и взаимодействия при решении поставленной задачи.
{% endhint %}

**Класс** – шаблон для объектов. **Каждый объект является экземпляром** (*instance*) **какого-либо класса** («безклассовых» объектов не существует). В рамках класса задается общий шаблон, структура, на основании которой создаются объекты. Данные, относящиеся к классу, называются **полями класса**, а программный код для их обработки называется **методами класса**. Поля и методы называют общим термином – **члены класса**.

Разница между классом и объектом такая же, как между абстрактным понятием и реальным объектом.

&#x20;Объект состоит из следующих частей:

* **имя** объекта;
* **состояние** (переменные состояния). Данные, содержащиеся в объекте, представляют его состояние. В терминологии ООП эти данные называются атрибутами. Например, атрибутами работника могут быть: имя, фамилия, пол, дата рождения, номер телефона. В разных объектах атрибуты имеют разное значение. Фактически, в объектах определяются конкретные значения тех переменных (полей класса), которые были заявлены при описании класса;
* **методы** (операции) – применяются для выполнения операций с данными, а также для совершения других действий. Методы определяют, как объект взаимодействует с окружающим миром.

В теории ООП, объекты могут отправлять друг другу сообщения. В языках программирования этот механизм реализуется через вызов функции другого объекта. Понятие "сообщение" в ООП можно объяснить следующим образом: мы не можем напрямую изменить состояние объекта и должны как бы послать сообщение объекту, что мы хотим как-то изменить его состояние. Очень важно понять, что объект сам меняет свое состояние, а мы можем только попросить его об этом с помощью отсылки сообщения.

**В объектно-ориентированной программе весь код должен находиться внутри классов!**&#x20;

В классе описываются, какого типа данные относятся к классу, а также то, какие методы применяются к этим данным. Затем, в программе на основе того или иного класса создается экземпляр класса (объект), в котором указываются конкретные значения полей и выполняются необходимые действия над ними.

### Классы как абстрактные типы данных

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

С ростом объема программы становится невозможным удерживать в памяти все детали, и становится необходимым структурировать информацию, выделять главное и отбрасывать несущественное. Этот процесс называется повышением степени **абстракции** программы.

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

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

Для работы с собственными типами данных требуются специальные функции. Естественно сгруппировать их с описанием этих типов данных в одном месте программы, а также по возможности отделить от ее остальных частей. При этом для использования этих типов и функций не требуется полного знания того, как именно они написаны - необходимы только описания интерфейсов. **Объединение в модули** описаний типов данных и функций, предназначенных для работы с ними, со скрытием от пользователя модуля несущественных деталей является дальнейшим развитием структуризации программы.

Все три описанных выше метода повышения **абстракции** преследуют цель упростить структуру программы, то есть **представить ее в виде меньшего количества более крупных блоков и минимизировать связи между ними**. Это позволяет управлять большим объемом информации и, следовательно, успешно отлаживать более сложные программы.

Введение понятия **класса** является естественным развитием идей модульности. В классе структуры данных и функции их обработки объединяются. **Класс** используется только через его **интерфейс** - детали реализации для пользователя класса не существенны.

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

**Класс** является типом данных, определяемым пользователем. В классе задаются свойства и поведение какого-либо предмета или процесса в виде полей данных (аналогично структуре) и функций для работы с ними. Создаваемый **тип данных** обладает практически теми же свойствами, что и стандартные (примитивные) типы (тип задает внутреннее **представление данных** в памяти компьютера, множество значений, которое могут принимать величины этого типа, а также **операции и функции**, применяемые к этим величинам).

Пользовательские типы данных принято называть абстрактными типами данных

Существенным **свойством класса** является то, что детали его реализации скрыты от пользователей класса за интерфейсом. Интерфейсом класса являются **заголовки его открытых методов**. Таким образом, **класс** как модель объекта реального мира является **черным ящиком**, замкнутым по отношению к внешнему миру.

Конкретные переменные типа данных "класс" называются **экземплярами класса**, или **объектами**. Объекты взаимодействуют между собой, посылая и получая сообщения. **Сообщение** - это **запрос** на выполнение действия, содержащий набор необходимых параметров. Механизм сообщений реализуется с помощью вызова соответствующих функций.

## Пример использования объектного подхода

Создадим класс `Box`, который описывает контейнер, допустим, на каком-то складе.

{% code title="Box.java" %}

```java
public class Box {
    
    double width;
    double height;
    double depth;
    
}
```

{% endcode %}

Класс `Box` определяет три переменные экземпляра: `width` (ширина), `height` (высота) и `depth` (глубина). В настоящий момент класс `Box` не содержит ник~~а~~ких методов.

Как мы уже говорили, класс определяет новый тип данных. В данном случае новый тип данных называется `Box`. Это имя будет использоваться для объявления объектов типа `Box`. Не следует забывать, что объявление `class` создает только шаблон, но не конкретный объект. Таким образом, приведенный выше код не приводит к появлению каких-нибудь объектов типа `Box`.

Чтобы действительно создать объект класса `Box`, нужно воспользоваться оператором `new`

{% code title="Main.java" %}

```java
public class Main {
    public static void main(String[] args) {

        Box myBox = new Box();
    }
}
```

{% endcode %}

После выполнения этого оператора объект `myBox` станет экземпляром класса `Box`. Таким образом, он обретет "физическое" существование.

Также следует напомнить, что каждый объект содержит собственную копию переменной экземпляра, которая определена в классе. Каждый объект типа `Box`будет содержать собственные копии переменных `width`, `height` и `depth`(рис. 4.2).

![Представление объектов в памяти](https://1377473627-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnhxGhlv6e_zwoZYywB%2F-LoGwivMxUDik5DfehB7%2F-LoH-lTYGfxSxa5VejFO%2Fassets_-LIEGYndXIZn8whSYtWl_-LWFn5TXHsu3zjFF5qQF_-LWFoSJdUSo_2USk7CUO_image.png?alt=media\&token=01efbbd8-5b7f-49f1-869f-044fc1d7ecba)

Изменения в переменных экземпляра одного объекта не влияют на переменные экземпляра другого объекта. Таким образом, каждый объект класса `Box` будет содержать собственные копии переменных `width`, `height` и `depth`. Для доступа к этим переменным служит оператор-точка `(.)`. Эта операция связывает имя объекта с именем переменной экземпляра. Например, чтобы присвоить переменной `width` экземпляра `myBox` значение 100, нужно выполнить следующий оператор:

```java
myBox.width = 100;
```

Этот оператор предписывает компилятору, что копии переменной `width`, хранящейся в объектe `myBox`, требуется присвоить значение 100. В общем, операция-точка служит для доступа как к переменным экземпляра, так и к методам в пределах объекта.&#x20;

Ниже приведет пример программы, в которой используется класс `Box`

{% tabs %}
{% tab title="Main.java" %}

```java
public class Main {
    public static void main(String[] args) {

        // Создаем объект типа Box
        Box myBox = new Box();

        // Присваиваем значения переменным экземпляра myBox
        myBox.width = 10;
        myBox.height = 20;
        myBox.depth = 15;

        // Рассчитываем объем коробки
        double volume = myBox.width * myBox.height * myBox.depth;

        System.out.println("Объем равен: " + volume);
    }
}
```

{% endtab %}

{% tab title="Box.java" %}

```java
public class Box {

    double width;
    double height;
    double depth;

}
```

{% endtab %}
{% endtabs %}

Как пояснялось ранее, каждый объект содержит собственные копии переменных экземпляра. Это означает, что при наличии двух объектов класса `Box` каждый из них будет содержать собственные копии переменных `width`, `height` и `depth`. Следует, однако, иметь ввиду, что изменения в переменных экземпляра одного объекта не влияют на переменные экземпляра другого. Например, в следующей программе объявлены два объекта класса `Box`:

```java
public class Main {
    public static void main(String[] args) {

        Box myBox1 = new Box();
        Box myBox2 = new Box();

        // Присваиваем значения для mybox1
        myBox1.width = 10;
        myBox1.height = 20;
        myBox1.depth = 15;

        // Присваиваем значения для mybox2
        myBox2.width = 3;
        myBox2.height = 6;
        myBox2.depth = 9;

        double volume;

        // объем первой коробки
        volume = myBox1.width * myBox1.height * myBox1.depth;
        // будет выведено 3000
        System.out.println("Объем равен: " + volume);

        // объем второй коробки
        volume = myBox2.width * myBox2.height * myBox2.depth;
        // будет выведено 162
        System.out.println("Объем равен: " + volume);
    }
}
```

Программа выводит следующий результат:

```
Объем равен: 3000.0
Объем равен: 162.0
```

Как видите, данные из объекта `myBox1` полностью изолированы от данных, содержащихся в объекте `myBox2`.

## Методы класса

Как упоминалось ранее, классы состоят из двух компонентов: переменных экземпляра и методов. Общая форма метода выглядит следующим образом:

```
[возвращаемый тип] имя ([список параметров]) {
    [тело метода]
}
```

где `возвращаемый тип` означает конкретный тип данных, возвращаемый методом. Он может быть любым допустимым типом данных, в том числе и типом созданного класса. Если метод не возвращает значение, то его возвращаемым типом должен быть `void`. В качестве имени методов может быть любой допустимый идентификатор, кроме тех, которые уже используются другими элементами кода в текущей области действия. А `список параметров` обозначает последовательность пар "тип-идентификатор", разделенных запятыми. По существу, параметры - это переменные, которые принимают значения аргументов, передаваемых методу во время его вызова. Если у метода отсутствуют параметры, то список параметров оказывается пустым. Методы, возвращаемый тип которых отличается от `void`, возвращают значение вызывающей части программы с помощью оператора `return`.

Вернемся к нашему примеру с классом `Box`. Было бы логично, если бы расчет объема коробки выполнялся в классе `Box`, поскольку объем коробки зависит от ее размеров. Для этого добавим в класс `Box` метод `getVolume()`

{% code title="Box.java" %}

```java
class Box {

    double width;
    double height;
    double depth;
    
    void getVolume() {
        System.out.print("Объем коробки равен ");
        System.out.println(width * height * depth);
    }
}
```

{% endcode %}

Внимательно рассмотрим две следующие строки кода

```java
mybox1.volume();
mybox2.volume();
```

В первой строке вызывается метод `volume()` для объекта `myBox1`. Следовательно, метод `volume()` вызывается по отношению к объекту `myBox1`, для чего было указано имя объекта, а вслед за ним - операция-точка. Таким образом, в результате вызова метода `myBox1.volume()` выводится объем коробки, определяемого объектом `myBox1`, а в результате вызова метода `myBox2.volume()` - объем коробки, определяемого объектом `myBox2`.

При вызове метода `myBox1.volume()` исполняющая система Jаvа передает управление коду, определенному в теле метода `volume()`. По окончании выполнения всех операторов в теле метода управление возвращается вызывающей части программы и далее ее выполнение продолжается со строки кода, следующей за вызовом метода. В самом общем смысле метод - это способ реализации подпрограмм в Java.

В методе `volume()` следует обратить внимание на еще одну очень важную особенность: ссылка на переменные экземпляра `width`, `height` и `depth` делается непосредственно без указания перед ними имени объекта или операции-точки. Когда в методе используется переменная экземпляра, определенная в его же классе, это делается непосредственно, без указания явной ссылки на объект и применения операции-точки . Это становится понятным, если немного подумать. Метод всегда вызывается по отношению к какому-то объекту его класса. Как только этот вызов сделан, объект известен. Таким образом, в теле метода вторичное указание объекта совершенно излишне. Это означает, что переменные экземпляра `width`, `height` и `depth` неявно ссылаются на копии этих переменных, хранящиеся в объекте, который вызывает метод `volume()`.&#x20;

Подведем краткие итоги. Когда доступ к переменной экземпляра выполняется из кода, не входящего в класс, где определена переменная экземпляра, следует непременно указать объект с помощью операции-точки. Но когда такой доступ осуществляется из кода, входящего в класс, где определена переменная экземпляра, ссылка на переменную может делаться непосредственно. Эти же правила относятся и к методам.

Следует обратить внимание, что метод `getVolume()` возвращает значение 3000, и это значение рассчитанного объема сохраняется в переменной `vol`. При обращении с возвращаемыми значениями следует принимать во внимание два важных обстоятельства:

* тип данных, возвращаемых методом, должен быть совместим с возвращаемым типом, указанным в методе. Так, если какой-нибудь метод должен возвращать логический тип **boolean**, то возвратить из него целочисленное значение нельзя;
* переменная, принимающая возвращаемое методом значение (например, `vol`), также должна быть совместима с возвращаемым типом, указанным для метода.
