JavaRush/Java блог/Java Developer/Знакомство с классами: написание собственных классов, кон...
Автор
Aditi Nawghare
Инженер-программист в Siemens

Знакомство с классами: написание собственных классов, конструкторы

Статья из группы Java Developer
участников
Привет! Сегодня мы поговорим о классах в Java. Классы — это, можно сказать, основа основ программирования на Java. Когда ты станешь программистом, твоей основной задачей будет написание собственных классов с разным функционалом. Знакомство с классами: написание собственных классов, конструкторы - 1Давай разберемся, что же это за штука такая и как она работает :) Как ты уже знаешь, 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) {

    }
}
Комментарии (2422)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Ilia
Уровень 14
17 апреля, 07:52
Дошел до 12 уровня и только после прочтения этой статьи понял зачем нужно слово static 😀
Сергей Дубакин
Уровень 15
Expert
15 апреля, 07:10
Отлично! Добротная статья! 👏👏👏
Asmadei
Уровень 15
24 марта, 07:22
Отличная и понятная статья, теперь понятно значения static!
{Java_Shark}
Уровень 19
1 марта, 13:33
Прекрасная информация!!! Автору огромное спасибо!!!:)
vlafriday
Уровень 4
20 февраля, 13:51
20.02.2024 check, мой уровень 3
Бромгексин
Уровень 16
11 марта, 12:38
все еще 3...
7 февраля, 11:07
Мне кажется для лучшего понимания, для новичка, переменные класса и присваивание им значений через конструктор лучше написать так. public class Cat { String catname; int catage; //конструктор для класса Cat public Cat(String name, int age) { this.catname = name; this.catage = age; }
Ivan Tanashev
Уровень 13
31 января, 13:27
Я думаю, abstraction не совсем верно локализировано на русский. Тут скорее подходит "абстрагирование", судя по описанию
AkkelaForest #3399225 Frontend Developer в LeverX
22 января, 12:47
Большое спасибо за эту статью! Наконец-то стало понятно значение static
Anastasia Я зеленый новичок в изучаю с нуля
18 декабря 2023, 14:03
Напишите пожалуйста, правильно ли я поняла, если упростить еще сильнее, до примитива: Класс - это место(файл). Типа оранжерея Объект - это предмет. Типа цветок в горшке Переменная - это деталь, она может быть деталью объекта (это поле). Типа цвет горшка - красный. Либо деталью класса(это переменная со словом static). Типа цвет оранжереи - зеленый. Массив - это много деталей в одном. Типа комода с деталями. Метод - это действия. Он может быть для предметов(т.е метод внутри которого будет работа с объектами), либо для деталей предмета(метод, внутри которого будет работа только с переменными) А абстракция - это место, где есть хранение, но нет действия. Типа комнаты хранилища, где хранятся семена нужных растений из оранжереи. Конструктор - это получается стикер на горшке, где написано что это за растение. Если нужно просто чтобы в оранжерее были растения в горшках - просто создаем обьект. Получается мы не должны ему сами прописывать конструктор, но он скрыто создастся по дефолту. А если мы хотим поместить напр в оранжерею 2 обьекта: красный апельсин и каенский перец - мы сначала создаем 2 обьекта: оба обьекты, и создаем им конструктор, в котором указываем что это красный апельсин и перец. Типа клеем стикер на каждое растение. А что написано на стикере - наши параметры, которые мы хотим написать. Правильно ли я все усвоила, отпишитесь плс, я совсем новичок
YUREC
Уровень 36
20 января, 11:26
Нет класс это не место и не файл и не оранжерея с объектом-цветком. Класс это ТИП ДАННЫХ такой же как integer,char или bool, только не примитивный, а составной, из переменных простых типов данных и относящихся к ним операциям (методам). А объект это переменная этого типа данных. Также как у объявления int X ; int будет типом данных(наподобие класса), а X будет переменной (наподобие объекта). Не понимаю почему в курсе не дают такого объяснения. Это объяснение из вузовского учебника по основам программирования. На мой взгляд оно исчерпывающее. И те кто учили до этого языки с составными типами данных, такими как record в паскале или struct в си, отлично понимают что класс это прежде всего тип данных, потому что такие составные типы это переходная стадия от примитивных типов к классам.
Anastasia Я зеленый новичок в изучаю с нуля
23 января, 12:28
Мне ваше обьяснение не понятно, и в вуз на программиста я не поступала. Как поняла, так и написала. Если вас такое обьяснение раздражает - можно было проигнорировать мой комментарий
YUREC
Уровень 36
24 января, 09:56
С чего вы решили что раздражает, я помочь хотел. А насчет непонятно ,ну даже не знаю, если вы знаете что такое примитивный тип данных и что такое переменная по идее должны понять что класс и объект это по сути тоже самое. Ну а если не знаете тогда к классам и объектам рано приступать, нужно подтянуть базу.
Anastasia Я зеленый новичок в изучаю с нуля
29 января, 10:10
У разных людей разный тип мышления. Если вы понимаете так, то другие могут понимать по другому. Это не значит что им нужно подтягивать базу. Это значит что нужно найти свой подход. Мне теоретические обьяснения из учебников не нравятся, как и не нравится обилие запутанных терминов. А нравится упрощение по принципу сравнения с обьектами из реального мира
YUREC
Уровень 36
1 февраля, 14:34
В программировании так нельзя, здесь как в математике если не знаешь как делить, умножать, возводить в степень и т.д. нельзя браться за квадратные уравнения. Так и здесь, не знаешь базы - что такое переменная, по каким принципам она работает, или плохо понимаешь функции, не сможешь понять и классы. Хоть какие аналогии выстраивай.
Scarry-77
Уровень 15
3 февраля, 18:02
возможно это неприятно слышать, но я полностью согласен с YUREC, вы можете сколь угодно пытаться понять темы , пытаясь провести аналогию с реальным миром, но ни к чему хорошему это не приведет, только запутаетесь
Ваня Корниенко
Уровень 48
17 декабря 2023, 17:17
Ставлю дизлайк, так как данная статья (иногда прямо целыми кусками с кодом и объяснениями) скопипасчена с другой, написанной ранее.
Evgeny Makarov
Уровень 13
20 декабря 2023, 22:52
Может, это более ранняя версия, убранная на полку доп. материалов? Вон и задачи какие-то в конце, но без самих задач, а Идеей без плагина JR пользоваться не учили ещё :\