Классы и объекты
Класс в Java — это шаблон для создания объекта, а объект — это экземпляр класса. Класс определяет структуру и поведение, которые будут совместно использоваться набором объектов. Класс содержит переменные и методы, которые называются элементами класса, членами класса. Он составляет основу инкапсуляции в Java. Каждый объект данного класса содержит структуру и поведение, которые определены классом. Иногда объекты называют экземплярами класса.
Методы используются для описания того, что объект класса умеет делать или что можно с ним сделать. Переменные — для описания свойств или характеристик объекта.
Рассмотрим картинку, приведенную ниже. Объявлен класс Student , у которого есть переменные name и rollNo , а также методы setName() и setRollNo() для установки этих значений. На основе этого класса создано несколько объектов: Jenna, John, Maria, James. У каждого объекта, то есть студента, есть name и rollNo , но они разные.
2. Как создать класс в Java
Рассмотрим как создать класс в языке Java. Упрощенная общая форма определения класса:
class ИмяКласса < тип переменнаяЭкземпляра1; тип переменнаяЭкземпляра2; // . тип переменнаяЭкземпляраN; тип имяМетода 1 ( список параметров) < // тело метода >тип имяМетода2 (список параметров) < // тело метода >… тип имяМетодаN (список параметров ) < // тело метода >>
После ключевого слова class пишется имя класса. В теле класса объявляются переменные и методы класса. Их может быть сколько угодно.
Опишем класс для объекта Box (коробка). У коробки есть три главные характеристики: ширина, высота и глубина, описанные с помощью переменных:
public class Box
3. Создание объекта в Java
Объявление класса создает только шаблон, но не конкретный объект. Чтобы создать объект класса Вох в Java, нужно воспользоваться оператором наподобие следующего:
Вох myBox = new Вох();
При создании экземпляра класса, создается объект, который содержит собственную копию каждой переменной экземпляра, определенной в данном классе.
Создание объектов класса представляет собой двух этапный процесс:
-
Объявление переменной типа класса. Эта переменная не определяет объект. Она является лишь переменной, которая может ссылаться на объект:
Вох myBox;
myBox = new Вох();
После объявления объекта класса Box , всем переменным класса присваивается значение по умолчанию для заданного типа. Для того чтобы обратиться к переменной класса и изменить ее или получить значение, используется имя переменной объекта:
public class BoxDemo1 < public static void main(String[] args) < 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); >>
В следующем примере объявляется два объекта класса Box и каждому устанавливаются свои значения. Изменения в переменных экземпляре одного объекта не влияют на переменные экземпляра другого.
public class BoxDemo7 < public static void main(String[] args) < Box myBox1 = new Box(); Box myBox2 = new Box(); double volume; // присвоить значения переменным экземпляра myBox1 myBox1.width = 10; myBox1.height = 20; myBox1.depth = 15; //присвоить другие значения переменным экземпляра myBox2 myBox2.width = 3; myBox2.height = 6; myBox2.depth = 9; // рассчитать объем первого параллелепипеда volume = myBox1.width * myBox1.height * myBox1.depth; System.out.println("Объем равен " + volume); // рассчитать объем второго параллелепипеда volume = myBox2.width * myBox2.height * myBox2.depth; System.out.println(" Объем равен " + volume); >>
4. Присваивание переменным ссылок на объекты
Возможна ситуация, когда две переменные указывают на один и тот же объект в памяти:
Рассмотрим как это происходит на следующем примере.
При объявлении переменной b1 создается новый объект в памяти. При объявлении переменной b2 , вместо создания нового объекта, переменной присваивается ссылка на объект b1 . Далее объекту, на который указывает переменная b1 , присваиваются значения 10, 20, 30. А ширине объекта, на который указывает переменная b2 , присваивается значение 3:
public class BoxDemo6 < public static void main(String[] args) < Box1 b1 = new Box1(); Box1 b2 = b1; b1.width = 10; b1.height = 20; b1.depth = 15; b2.width = 3; System.out.println("Width: " + b1.width); System.out.println("Width: " + b2.width); >>
Но обе переменные указывают на один и тот же объект, поэтому результат выполнения этой программы будет:
Width: 3.0 Width: 3.0
5. Добавляем методы в класс
Кроме переменных класс может содержать методы. В следующем примере в класс Box добавляется два метода: getVolume() — для вычисления объема коробки и setDim() — для установки размера коробки. Обратите внимание, что теперь мы объявляем методы нестатические (без ключевого слова static). В обоих методах мы имеем доступ к переменным класса.
public class Box < double width; double height; double depth; /** * Подсчитать объем коробки * * @return Объем */ double getVolume() < return width * height * depth; >/** * Установить размер коробки * * @param w - ширина * @param h - высота * @param d - глубина */ void setDim(double w, double h, double d) < width = w; height = h; depth = d; >>
В следующей программе создаются два объекта класса Box и вместо инициализации каждой переменной класса, как мы делали ранее, вызывается метод setDim() , куда передаются необходимые значения для ширины, высоты и глубины. Таким образом программа становится более компактной. Нестатический метод класса всегда вызывается для какого-то объекта. Аналогично, для подсчета объема коробки вызываем метод getVolume() для каждого объекта отдельно:
public class BoxDemo2 < public static void main(String[] args) < Box myBox1 = new Box(); Box myBox2 = new Box(); myBox1.setDim(10, 20, 15); myBox2.setDim(1, 5, 5); System.out.println("Объем: " + myBox1.getVolume()); System.out.println("Объем: " + myBox2.getVolume()); >>
- Процедурное и объектно-ориентированное программирование
- Принципы ООП
- Конструктор
- Ключевое слово this
- Перегрузка
- Стек и куча
- Передача объектов в методы
- Java varargs
- Рекурсия
- Сборщик мусора и метод finalize
- Наследование
- Ключевое слово super
- Модификаторы доступа
- Геттеры и сеттеры
- Переопределение методов
- Абстрактные классы и методы
- Ключевое слово final
- Задания
Объекты — Java: Введение в ООП
Так в чем же состоит настоящая цель классов? Упрощенно, с помощью классов описываются категории объектов, например, «кошки» или «адреса» или даже «строки». На базе классов создаются объекты, из которых потом строится логика работы кода.
Возьмем для примера студента Хекслета. В коде он описан классом User , у которого есть свойства и методы. Свойства — это любая информация о пользователе: дата рождения, дата создания, имя, наличие доступов и т.п. Методы – действия которые может выполнять пользователь.
Такой стиль работы предполагает, что класс используется как «шаблон» для создания объектов этого класса (или как говорят «экземпляров класса»). Например, для класса User объектами будут конкретные пользователи:
// Создание объекта пользователя (или просто пользователя) // из класса User // первый параметр - имя // второй параметр - фамилия var user = new User("Danil", "Miloshin"); // метод возвращает имя user.getFirstName(); // "Danil" // метод возвращает фамилию user.getLastName(); // "Miloshin" // метод возвращает полное имя user.getFullName(); // "Danil Miloshin"
В коде мы создаем объект «пользователь» с указанными именем и фамилией. Делается это с помощью ключевого слова new , после которого идет имя класса со скобками, как при вызове обычной функции. Этот объект записывается в переменную и становится доступен для работы. Дальше, в зависимости от того как был написан класс, мы можем выполнять разные действия с ним — менять свойства и вызывать методы. Это похоже на работу со строками, только в таких объектах как выше, хранится не одно значение, а какой-то набор разнородных данных. Причем они могут быть разных типов. Вот пример другого класса User , который мы могли бы написать:
// первый параметр - email // второй параметр - возраст var user = new User("admin@hexlet.io", 25); // Это не статический метод // он взаимодействует с конкретным объектом и имеет доступ к его данным user.getEmail(); // "admin@hexlet.io"
При таком подходе, программа превращается в набор объектов, которые взаимодействуют друг с другом. Через эти объекты выражаются процессы, происходящие в проекте. Например, создание курса, добавление туда уроков, прохождение курса студентом и так далее. Все это в коде выглядит как объекты, жонглирующие объектами:
// Гипотетический пример – Создание курса // Даже даты это объекты var course = new Course("java", "тут описание", new Date()); var lesson1 = new Lesson("строки", "тут текст"); course.addLesson(lesson1); // добавляем урок в курс var lesson2 = new Lesson("числа", "тут текст"); course.addLesson(lesson2); // и еще один repository.save(course); // сохранение в базу данных course.getLessons(); // вернет два урока
В программировании такой стиль программирования называется объектно-ориентированным (ООП). Чтобы научиться писать такой код, нужно время. В начале, для создания объектов, мы будем использовать или дописывать готовые классы. Затем, постепенно, вы начнете создавать свои, пока это не станет обыденным делом.
Связь с реальным миром
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Класс Object
В Java есть специальный суперкласс Object и все классы являются его подклассами. Поэтому ссылочная переменная класса Object может ссылаться на объект любого другого класса. Так как массивы являются тоже классами, то переменная класса Object может ссылаться и на любой массив.
// применимо к любому классу Object obj = new Cat("Barsik");
В таком виде объект обычно не используют. Чтобы с объектом что-то сделать, нужно выполнить приведение типов.
Cat cat = (Cat) obj;
У класса есть несколько важных методов.
- Object clone() — создаёт новый объект, не отличающий от клонируемого
- boolean equals(Object obj) — определяет, равен ли один объект другому
- void finalize() — вызывается перед удалением неиспользуемого объекта
- Class getClass() — получает класс объекта во время выполнения
- int hashCode() — возвращает хеш-код, связанный с вызывающим объектом
- void notify() — возобновляет выполнение потока, который ожидает вызывающего объекта
- void notifyAll() — возобновляет выполнение всех потоков, которые ожидают вызывающего объекта
- String toString() — возвращает строку, описывающий объект
- void wait() — ожидает другого потока выполнения
- void wait(long millis) — ожидает другого потока выполнения
- void wait(long millis, int nanos) — ожидает другого потока выполнения
Методы getClass(), notify(), notifyAll(), wait() являются финальными и их нельзя переопределять.
Метод hashCode()
Хеш-код — это целое число, генерируемое на основе конкретного объекта. Его можно рассматривать как шифр с уникальным значением.
Для вычисления хеш-кода в классе String применяется следующий алгоритм.
int hash = 0; for(int i = 0; i < length(); i++) hash = 31 * hash + charAt(i);
У любого объекта имется хеш-код, определяемый по умолчанию, который вычисляется по адресу памяти, занимаемой объектом.
Значение хеш-кода возвращает целочисленное значение, в том числ и отрицательное.
Если в вашем классе переопределяется метод equals(), то следует переопределить и метод hashCode().
Метод toString()
Очень важный метод, возвращающий значение объекта в виде символьной строки.
Очень часто при использовании метода toString() для получения описания объекта можно получить набор бессмысленных символов, например, [I@421199e8. На самом деле в них есть смысл, доступный специалистом. Он сразу может сказать, что мы имеем дело с одномерным массивом (одна квадратная скобка), который имеет тип int (символ I). Остальные символы тоже что-то означают, но вам знать это не обязательно.
Если же вам нужно научное объяснение, то метод работает по следующему алгоритму (из документации).
getClass().getName() + '@' + Integer.toHexString(hashCode())
Обычно принято переопределять метод, чтобы он выводил результат в читаемом виде.
Создание объектов в Java
Создание объектов в Java и связывание их с переменными чаще всего выглядит так:
Second second = new Second();
В правой части с помощью ключевого слова new создается объект от класса Second. Созданный объект присваивается переменной second, чей тип указывается перед именем переменной. В случае наличия наследственных связей тип переменной может не совпадать с типом создаваемого объекта.
public class Main public static void main(String[] args) Second second = new Second(); > >
class Second Second() System.out.println("Object created"); > >
В классе Second есть только один метод – это конструктор. В данном случае, когда создается объект, на экран будет выведено сообщение.
Когда мы используем библиотечные классы Java, например String, то создаем объекты также. Выражение
String str = "Hello";
String str = new String("Hello");
Переменные можно сначала объявлять, а потом присваивать им значения:
String str; str = "Hello";
В Java переменные объектных типов являются ссылочными, то есть хранят не сам объект, а ссылку на него. Отсюда следует, что 1) методы классов меняют переданные им в качестве аргументов объекты, и 2) на один объект может ссылаться множество переменных.
Переменной-ссылке можно присвоить значение null. Такая переменная начинает ссылаться на адрес 0. Виртуальная машина Java воспринимает указание на этот адрес как отсутствие объекта.
Обнуление ссылочной переменной ведет к уничтожению хранимого в памяти объекта только в том случае, если нет других ссылок-переменных на него.
В Java не все объекты создаются с помощью классов. Существуют примитивные типы: пять целочисленных (byte, char, short, int, long), два вещественных (float и double) и булев тип (boolean). При объявлении переменных этих типов используется маленькая буква в названии типа. Например:
int number; double pi = 3.14;
Если переменная примитивного типа передается в функцию в качестве аргумента, то никакая ссылка на объект туда не передается, происходит копирование значения переменной. Другими словами, действия внутри метода не изменяют значения переданных переменных.
В Java все объекты преобразуются к строковому типу при выводе на экран. При этом для объектов неявно вызывается метод toString родительского класса Object, от которого наследуются все классы. В случае необходимости метод можно вызывать явно. Следующие две строки равносильны:
System.out.println(second); System.out.println(second.toString());
Метод toString() класса Object возвращает строку, состоящую из имени класса и шестнадцатеричного адреса объекта в памяти. То есть по умолчанию вывод будет примерно такой:
Second@1540e19d
Понятно, что можно переопределить метода toString() в дочернем классе:
@Override public String toString() return "It's the second object"; >
В случае примитивных типов явное преобразование к строке происходит через вызов метода аналогичного типу класса:
int b = 100; String s = Integer.toString(b); // String s = b.toString(); - ошибка
В Java есть классы Integer, Double и др. Однако использование примитивных типов выгодней с точки зрения экономии памяти.
X Скрыть Наверх
Программирование на Java. Курс