# 3. Понятие класса и объекта

## 1. Понятие объекта

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

* имя объекта;
* состояние (данные объекта, переменные состояния). Состояние объекта характеризуется перечнем всех свойств данного объекта и текущими значениями каждого из этих свойств;
* методы (операции).

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

**Поведение объектов.** Поведение объекта – то, что он может сделать (в структурном программировании это реализовывалось функциями, процедурами, подпрограммами).

**Сообщения** – механизм коммуникации между объектами. Например, когда объект А вызывает метод объекта B, объект A отправляет сообщение объекту B. Ответ объекта B определяется его возвращаемым значением. Только «открытые» методы могут вызываться другим объектом.

## 2. Понятие класса

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

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

Согласно конвенции кода и правилам языка Java:

* каждый класс должен содержаться в своем отдельном файле с расширением .java;&#x20;
* название файла должно совпадать с названием класса;
* класс должен быть именем существительным;
* имя класса должно его описывать;
* имя класса начинается с большой буквы;
* если имя состоит из нескольких слов, то каждое слово начинается с большой буквы.

Рассмотрим разницу между объектом и классом на примере. Определим класс `Cat`и `Dog`. Описание класса производится через указание полей (данных) и методов класса. Для класса `Cat`в качестве полей укажем `name`(кличку кота) и `color`(окрас). Для класса `Dog`задаем поля `name`(кличка), `color`(окрас) и `breed`(порода).

{% tabs %}
{% tab title="Класс Dog" %}
```java
class Dog {

    String name;
    String color;
    String breed;

    void bark() {
        // Лаять
    }

    void fawn() {
        // Вилять хвостом
    }
}
```
{% endtab %}

{% tab title="Класс Cat" %}
```java
class Cat {

    String name;
    String color;

    void catchMouse() {
        // Ловить мышей
    }

    void mew() {
        // Мяучить
    }
}
```
{% endtab %}
{% endtabs %}

Помимо полей, определим методы для этих классов. **Методы** – это то, что может делать объект класса (или что можно делать с объектом). Коты будут мяукать, и ловить мышей, а собаки лаять и вилять хвостом.

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

## 3. Синтаксис классов

Рассмотрим синтаксис описания классов в Java. Описание класса начинается с ключевого слова class. После этого следует имя класса и в фигурных скобках тело класса. Тело класса состоит из описания членов класса – полей и методов.

![](https://1377473627-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnhxGhlv6e_zwoZYywB%2F-LoGwivMxUDik5DfehB7%2F-LoH-f_4TnyUZf552MDQ%2Fassets_-LIEGYndXIZn8whSYtWl_-LWFn5TXHsu3zjFF5qQF_-LWFoMJVAsTEXFgW1Sby_image.png?alt=media\&token=60d9340a-7af4-4c18-9b47-376297deefbd)

Для объявления класса служит ключевое слово **class**. Упрощенная форма определения класса имеет вид:

```
class имя_класса {
    тип переменная_экземпляра_1;
    тип переменная_экземпляра_2;
    тип переменная_экземпляра_3;
...
    тип переменная_экземпляра_N;

    тип имя_метода_1(список параметров) {...}
    тип имя_метода_2(список параметров) {...}
...
    тип имя_метода_N(список параметров) {...}
}
```

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

Код содержится в теле методов. В большинстве классов действия над переменными и доступ к ним осуществляют методы этого класса. Таким образом, методы определяют порядок использования данных класса.

## 4. Пример простого класса

Создадим класс `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).

![Рисунок 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`.

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

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

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

где `возвращаемый тип` означает конкретный тип данных, возвращаемый методом. Он может быть любым допустимым типом данных, в том числе и типом созданного класса. Если метод не возвращает значение, то его возвращаемым типом должен быть `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`), также должна быть совместима с возвращаемым типом, указанным для метода.
