Привет! Сегодня мы поговорим о классах в Java.
Классы — это, можно сказать, основа основ программирования на Java. Когда ты станешь программистом, твоей основной задачей будет написание собственных классов с разным функционалом.
Давай разберемся, что же это за штука такая и как она работает :)
Как ты уже знаешь, Java — это объектно-ориентированный язык программирования. Все программы состоят из объектов, которые как-то связываются между собой.
Класс — это, по сути, шаблон для объекта. Он определяет, как объект будет выглядеть и какими функциями обладать. Каждый объект является объектом какого-то класса.
Рассмотрим самый простой пример:

public class Cat {
String name;
int age;
}
Допустим, мы пишем программу, и в этой программе нам для чего-то нужны кошки (например, у нас ветеринарная клиника с возможностью онлайн-записи).
Мы создали класс Cat
, и указали для него две переменные — строку name
, и число age
. Такие переменные классов называются полями.
По сути — это шаблон для всех кошек, которых мы создадим в будущем. У каждой кошки (объекта класса Cat
) будет две переменные — имя и возраст.
public class Cat {
String name;
int age;
public static void main(String[] args) {
Cat barsik = new Cat();
barsik.age = 3;
barsik.name = "Барсик";
System.out.println("Мы создали кота по имени " + barsik.name + ", его возраст - " + barsik.age);
}
}
Вот так это работает! Мы создали кота, присвоили ему имя и возраст и вывели все это в консоль. Ничего сложного :)
Классы чаще всего описывают предметы и явления окружающего мира.
Кошка, стол, человек, молния, страница книги, колесо — все это в твоей программе будет создаваться с помощью отдельных классов.
Теперь давай обратим внимание на переменные, которые мы создали в классе Cat
. Они называются полями, или переменными экземпляров. В названии, собственно, раскрыта вся их суть. Эти переменные будут у каждого экземпляра (объекта) класса Cat
. У каждого кота, которого мы создадим, будет своя переменная name
и своя переменная age
. Логично, в общем-то: с настоящими котами все так и есть :)
Кроме переменных экземпляров существуют и другие — переменные классов, или статические. Дополним наш пример:
public class Cat {
String name;
int age;
static int count = 0;
public static void main(String[] args) {
Cat barsik = new Cat();
barsik.age = 3;
barsik.name = "Барсик";
count++;
Cat vasia = new Cat();
vasia.age = 5;
vasia.name = "Вася";
count++;
System.out.println("Мы создали кота по имени " + barsik.name + ", его возраст - " + barsik.age);
System.out.println("Мы создали кота по имени " + vasia.name + ", его возраст - " + vasia.age);
System.out.println("Общее количество котов = " + count);
}
}
Вывод в консоль:
Мы создали кота по имени Барсик, его возраст - 3
Мы создали кота по имени Вася, его возраст - 5
Общее количество котов = 2
Теперь у нас в классе появилась новая переменная — count
(количество). Она отвечает за подсчет созданных котов. Каждый раз, когда в методе main мы создаем кота, мы увеличиваем эту переменную на 1.
Эта переменная обозначена ключевым словом static. Это значит, что она принадлежит классу, а не конкретному объекту класса. Что, конечно, логично: если имя у каждого кота должно быть свое, то счетчик котов нам нужен один на всех. Именно этого позволяет добиться слово static — переменная count
одна для всех котов.
Обрати внимание: когда мы выводим ее в консоль, мы не пишем barsik.count
или vasia.count
. Она не принадлежит ни Барсику, ни Васе — она принадлежит всему классу Cat
. Поэтому — просто count
.
Можно также написать Cat.count
— это тоже будет правильно.
С выводом в консоль переменной name
у нас бы такое не прошло:
public class Cat {
String name;
int age;
static int count = 0;
public static void main(String[] args) {
Cat barsik = new Cat();
barsik.age = 3;
barsik.name = "Барсик";
count++;
System.out.println("Мы создали кота по имени " + name + ", его возраст - " + barsik.age);
System.out.println("Общее количество котов = " + count);
}
}
Ошибка! name
у каждого кота свое. В этом месте компилятор сбивается с толку.
"Вывести в консоль имя? А чье имя-то? :/"
Методы
Кроме переменных, у каждого класса есть методы. О них мы поговорим в отдельной лекции более подробно, но общие моменты довольно просты. Методы — это функционал твоего класса; то, что объекты этого класса умеют делать. С одним из методов ты уже знаком — это методmain()
. Но метод main
, как ты помнишь, является статическим — то есть он принадлежит всему классу (логика такая же, как с переменными).
А обычные, нестатические методы, можно вызывать только на конкретных объектах, которые мы создали.
Например, если мы хотим написать класс для кошки, нам надо понять, какими функциями кошка должна обладать в нашей программе. Исходя из этого, напишем для нее пару методов:
public class Cat {
String name;
int age;
public void sayMeow() {
System.out.println("Мяу!");
}
public void jump() {
System.out.println("Прыг-скок!");
}
public static void main(String[] args) {
Cat barsik = new Cat();
barsik.age = 3;
barsik.name = "Барсик";
barsik.sayMeow();
barsik.jump();
}
}
Ну вот, теперь наш класс гораздо больше похож на описание настоящей кошки! У нас теперь не просто кот Барсик с именем и возрастом. Он еще умеет мяукать и прыгать! Какой же кот без такого "функционала" :)
Берем конкретный объект — barsik
, и вызываем у него методы sayMeow()
и jump()
.
Смотрим в консоль:
Мяу!
Прыг-скок!
Настойщий кот! :)
Создание собственных классов. Абстракция
В будущем тебе придется писать собственные классы. На что нужно обратить внимание при их написании? Если мы говорим о переменных, тебе нужно пользоваться такой вещью как абстракция. Абстракция — один из четырех основных принципов объектно-ориентированного программирования. Он подразумевает выделение главных, наиболее значимых характеристик предмета, и наоборот — отбрасывание второстепенных, незначительных. Например, мы создаем картотеку работников компании. Для создания объектов "работник" мы написали классEmployee
. Какие характеристики важны для описания работника в картотеке компании? ФИО, дата рождения, номер социального страхования, ИНН. Но вряд ли в карточке работника компании нам нужны его рост, цвет глаз и волос. Компании эта информация ни к чему.
Поэтому для класса Employee
мы зададим переменные String name
, int age
, int socialInsuranceNumber
и int taxNumber
, а от лишней для нас информации (типа цвета глаз) откажемся, абстрагируемся.
А вот если мы создаем картотеку фотомоделей для модельного агентства, ситуация резко меняется. Для описания фотомодели нам как раз очень важны рост, цвет глаз и цвет волос, а вот номер ИНН для нее нам абсолютно не важен.
Поэтому в классе Model
нам нужно создать переменные int height
, String hair
, String eyes
.
Вот так и работает абстракция, все просто! :)
Конструкторы
Давай вернемся к нашему примеру с кошками.
public class Cat {
String name;
int age;
public static void main(String[] args) {
Cat barsik = new Cat();
System.out.println("Тут в программе в течение 2-х часов что-то происходит...");
barsik.age = 3;
barsik.name = "Барсик";
}
}
Посмотри на этот код и попробуй догадаться, что с нашей программой не так.
На протяжении двух часов в нашей программе существовал кот без имени и возраста!
Конечно, это в корне неверно. В базе данных ветеринарной клиники не должно быть котов без информации о них.
Сейчас мы отдаем это на откуп программиста. Не забудет он указать имя и возраст — все будет ок. Забудет — в базе будет ошибка, неизвестные коты.
Как нам решить эту проблему? Надо каким-то образом запретить создавать котов без имени и возраста.
Здесь нам на помощь приходят функции-конструкторы.
Приведем пример:
public class Cat {
String name;
int age;
//конструктор для класса Cat
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Cat barsik = new Cat("Barsik", 5);
}
}
Конструктор — это, по сути, шаблон для объектов класса.
В данном случае мы указывем, что для каждого объекта cat
должны быть указаны два аргумента — строка и число.
Если мы теперь попытаемся создать безымянного кота — у нас это не получится.
public class Cat {
String name;
int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Cat barsik = new Cat(); //ошибка!
}
}
Теперь, когда в классе есть конструктор, компилятор Java знает, как должны выглядеть объекты, и не позволяет создавать объекты без указанных в нем аргументов.
Теперь давай разберемся с ключевым словом this
, которое ты видишь внутри конструктора.
С ним тоже все просто.
"this" по-английски — "этот, этого". То есть это слово указывает на конкретный предмет.
Код в конструкторе
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
можно перевести почти дословно:
"name для этого кота (которого мы создаем) = аргументу name, который указан в конструкторе. age для этого кота (которого мы создаем) = аргументу age, который указан в конструкторе."
После срабатывания конструктора можешь проверить, что нашему коту присвоились все нужные значения:
public class Cat {
String name;
int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Cat barsik = new Cat("Барсик", 5);
System.out.println(barsik.name);
System.out.println(barsik.age);
}
}
Вывод в консоль:
Барсик
5
Когда конструктор отработал:
Cat barsik = new Cat("Барсик", 5);
Внутри него по факту произошло следующее:
this.name = "Барсик";
this.age = 5;
И объекту barsik
(он и является this
) присвоились значения из аргументов конструктора.
На самом деле, если не указать в классе конструкторы у него все равно будет срабатывать конструктор!
Но как такое возможно? О_О
Дело в том, что в Java у всех классов есть так называемый конструктор по умолчанию. У него нет никаких аргументов, но он срабатывает каждый раз при создании любого объекта любого класса.
public class Cat {
public static void main(String[] args) {
Cat barsik = new Cat(); //вот здесь сработал конструктор по умолчанию
}
}
На первый взгляд это не заметно. Ну создали объект и создали, где тут работа конструктора?
Чтобы это увидеть, давай прямо руками напишем для класса Cat
пустой конструктор, а внутри него выведем какую-нибудь фразу в консоль. Если она выведется, значит конструктор отработал.
public class Cat {
public Cat() {
System.out.println("Создали кота!");
}
public static void main(String[] args) {
Cat barsik = new Cat(); //вот здесь сработал конструктор по умолчанию
}
}
Вывод в консоль:
Создали кота!
Вот и подтверждение. Конструктор по умолчанию всегда незримо присутствует в твоих классах.
Но тебе нужно знать еще одну его особенность.
Дефолтный конструктор исчезает из класса, когда ты создаешь какой-то конструктор с аргументами.
Доказательство этого, на самом деле, мы уже видели выше. Вот в этом коде:
public class Cat {
String name;
int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Cat barsik = new Cat(); //ошибка!
}
}
Мы не смогли создать кота без имени и возраста, потому что определили конструктор для Cat
: строка + число.
Дефолтный конструктор сразу после этого исчез из класса.
Поэтому обязательно запомни: если тебе в твоем классе нужно несколько конструкторов, включая пустой, его нужно создать отдельно.
Например, наша ветеринарная клиника хочет делать добрые дела и помогать бездомным котикам, чьих имен и возраста мы не знаем.
Тогда наш код должен выглядеть так:
public class Cat {
String name;
int age;
//для домашних котов
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
//для уличных котов
public Cat() {
}
public static void main(String[] args) {
Cat barsik = new Cat("Barsik", 5);
Cat streetCat = new Cat();
}
}
Теперь, когда мы явно указали конструктор по умолчанию, мы можем создавать котов обоих типов.
В конструкторе можно присваивать значения и явно, а не только брать их из аргументов. Например, мы можем записывать всех уличных котов в базу данных под именем "Уличный кот номер..." :
public class Cat {
String name;
int age;
static int count = 0;
public Cat() {
count++;
this.name = "Уличный кот номер " + count;
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Cat streetCat1 = new Cat();
Cat streetCat2 = new Cat();
System.out.println(streetCat1.name);
System.out.println(streetCat2.name);
}
}
У нас есть переменная count
, которая является счетчиком уличных котов.
Каждый раз при выполнении конструктора по умолчанию мы увеличиваем ее на 1 и присваем этот номер в качестве имени кота.
Для конструктора очень важен порядок следования аргументов.
Поменяем в нашем конструкторе аргументы имени и возраста местами.
public class Cat {
String name;
int age;
public Cat(int age, String name) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Cat barsik = new Cat("Барсик", 10); //ошибка!
}
}
Ошибка! Конструктор четко описывает: при создании объекта Cat
ему должны быть переданы число и строка, именно в таком порядке. Поэтому наш код не срабатывает.
Обязательно запомни это и учитывай при создании своих собственных классов:
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
Это два абсолютно разных конструктора!
Теперь реши несколько задач на закрепление материала :)
- Музей древностей.
Artifact
.
Артефакты, которые хранятся в музее, бывают трех видов.
Первый — о которых неизвестно ничего, кроме порядкового номера, присвоенному музеем (например: 212121).
Второй — о которых известен порядковый номер и культура, которой он был создан (например: 212121, "Ацтеки").
Третий вид — о которых известен порядковый номер, культура, которой он был создан, и точный век его создания (например: 212121, "Ацтеки", 12).
Создай класс Artifact
, описывающий хранящиеся в музее древности, и напиши необходимое количество конструкторов для него. В методе main()
создай по одному артефакту каждого вида.
public class Artifact {
public static void main(String[] args) {
}
}
- Сайт знакомств
User
, у которого будут поля — имя (String
) возраст (short
) и рост (int
).
Создайте для него необходимое количество конструкторов, чтобы имя, возраст и рост можно было указывать в любом порядке.
public class User {
String name;
short age;
int height;
public static void main(String[] args) {
}
}
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ