<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 17:23:35 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="s3Hwa1053-6DCf2Tv-Ofz-lLy8QbEew9Dv56JC45dZtcoDtcr0dyjjVK2Quz7G-4KULmbhMmEp-zHuBwfD6S9Q";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Интерфейсы | Java: Введение в ООП</title>
<meta name="description" content="Интерфейсы / Java: Введение в ООП: Знакомимся с концепцией интерфейсов, которые ведут нас к светлому полиморфизму">
<link rel="canonical" href="https://ru.hexlet.io/courses/java-oop-basics/lessons/interfaces/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Интерфейсы">
<meta property="og:title" content="Java: Введение в ООП">
<meta property="og:description" content="Интерфейсы / Java: Введение в ООП: Знакомимся с концепцией интерфейсов, которые ведут нас к светлому полиморфизму">
<meta property="og:url" content="https://ru.hexlet.io/courses/java-oop-basics/lessons/interfaces/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="KSelR34LJXou5pRG40LjcAY7XL3YadkHmMx9bVbX2E_G9m5wjHWIGpilsN7vTRMHxjJxF9BeJ6UlLOc5BNA_IQ" />
<script src="/vite/assets/inertia-INZxX8jp.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-6pOtQ3OW.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzczNSwicHVyIjoiYmxvYl9pZCJ9fQ==--883f3fd4e1b571538035b5680c8d4a9eb504b1f6/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Source%20code-amico.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzkyMywicHVyIjoiYmxvYl9pZCJ9fQ==--da8237868b3f1c36e3fe891b47b4869fa9f2e8ef/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Bug%20fixing-pana.png"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T17:23:35.215Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"cXMIEDvAsasFQQfYkTxW_KnsLKLAZBxk8oR45sZfkc6eosMnyb4cy7MCI0CdM6aLaeUBCMhT4sZPZOKylFh2oA","topics":[{"id":65784,"title":"Добрый день!\nНикак не дается мне интерфейс.\nПодскажите, что я делаю не так.\nhttps://ru.hexlet.io/code_reviews/568421\n","plain_title":"Добрый день! Никак не дается мне интерфейс. Подскажите, что я делаю не так. https://ru.hexlet.io/code_reviews/568421 ","creator":{"public_name":"Алексей Гороховатский","id":437524,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Gagarinov","id":75907,"is_tutor":true},"id":138319,"body":"**Алексей**, здравствуйте! Посмотрите ещё раз внимательно теорию, как там создаётся класс `SimplePasswordGenerator` с использованием интерфейса и сравните с тем, как у вас создаётся класс `Quadrate`. В вашем решении в этом классе почему-то создаётся объект `new Quadrate()`. Второй момент, метод `getFigureSquare()` в классе `App` должен принимать не класс фигуры, а сам объект этого класса. И в методе у вас вызываются методы `App.getName()` и `App.getSquare()` которых нет в классе `App`. Эти методы должны быть в объекте фигуры, который приходит в параметры метода.","topic_id":65784},{"creator":{"public_name":"Екатерина Лучанова","id":362531,"is_tutor":false},"id":146512,"body":"**Екатерина Лучанова**, Непонятно мне... Класс реализует интерфейс Geometric, и нужно определить в нём методы getName() и getSquare()., что я и сделала. Однако, при проверке выходит вот такая ошибка: Quadrate.java:[12,9] getSquare() in io.hexlet.Quadrate cannot implement getSquare() in io.hexlet.Geometric\n attempting to assign weaker access privileges; was public\nЧто это значит?","topic_id":65784},{"creator":{"public_name":"Екатерина Лучанова","id":362531,"is_tutor":false},"id":146330,"body":"Бьюсь, бьюсь, но не понимаю выводов тестов. Вопросы:\n1. Нужно ли импортировать интерфейс Geometric в класс Quadrate, и нужно ли импортировать класс Quadrate в App? \n\n2. И вот вопрос про Quadrate.java. Класс реализует интерфейс Geometric, и в классе должен быть конструктор. В интерфейсе не может быть конструктора. Я запуталась.... Я в том месте создала конструктор (это же класс, реализующий интерфейс, а не сам интерфейс, правильно?) или не в том? Памагити.....\n\nhttps://ru.hexlet.io/code_reviews/632518","topic_id":65784},{"creator":{"public_name":"Екатерина Лучанова","id":362531,"is_tutor":false},"id":147024,"body":"**Екатерина Лучанова**, починила сама, указав public перед методами в классе Quadrate. Но раз они заведомо публичны в интерфейсе, зачем нужно было указывать public в Quadrate?.. Не очень понимаю пока.","topic_id":65784}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":69754,"title":"Добрый день!\nВроде поправил. Но не могу понять, как создать класс App, что бы в нем корректно обрабатывались классы геометрических фигур.\nhttps://ru.hexlet.io/code_reviews/568421\n","plain_title":"Добрый день! Вроде поправил. Но не могу понять, как создать класс App, что бы в нем корректно обрабатывались классы геометрических фигур. https://ru.hexlet.io/code_reviews/568421 ","creator":{"public_name":"Алексей Гороховатский","id":437524,"is_tutor":false},"comments":[{"creator":{"public_name":"Алексей Гороховатский","id":437524,"is_tutor":false},"id":146108,"body":"Спасибо. Получилось. Надо еще осмыслить.\n","topic_id":69754},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":146189,"body":"Алексей, если будут еще вопросы, спрашивайте","topic_id":69754},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":146049,"body":"Приветствую, Алексей! Сейчас в классе два метода `getFigureSquare()` с одинаковыми сигнатурами, именно поэтому и возникает ошибка. \n\n```\nmethod getFigureSquare(io.hexlet.Geometric) is already defined in class io.hexlet.App\n```\n\nОставьте только метод. Ведь и круг и квадрат реализуют интерфейс `Geometric`, поэтому метод с такой сигнатурой может обрабатывать и круг и квадрат и любую другую фигуру, которая реализует этот интерфейс. Ведь методы `getName()` и `getSquare()` обязательно будут в классе каждой фигуры","topic_id":69754}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":67791,"title":"Довольно сложно описана теория. Единственная тема в модуле которую так и не понял. Пришлось дополнительно искать информацию на сторонних ресурсах.","plain_title":"Довольно сложно описана теория. Единственная тема в модуле которую так и не понял. Пришлось дополнительно искать информацию на сторонних ресурсах. ","creator":{"public_name":"Vitalii Semenov","id":456885,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":142020,"body":"Приветствую, Виталий! А можете немного подробнее рассказать, с чем возникли затруднения в уроке, что оказалось не понятным? Это здорово поможет нам сделать урок лучше","topic_id":67791},{"creator":{"public_name":"Vitalii Semenov","id":456885,"is_tutor":false},"id":142070,"body":"Приветствую, Максим. Попробую подробнее) Лично мне не хватило информации, а для чего собственно нужны интерфейсы, как выяснилось через них организовано множественное наследование в классах. При чем как выяснилось требования к классам, описанные в интерфейсе являются обязательными для классов, в которых их необходимо реализовать. Что такое \"реализация\" тоже из теории плохо понятно, во всяком случае мне было. Ну и пример бы не помешал) абстрактный) Мне понравился пример с интерфейсом \"фигуры\" и производные от него классы \"квадрат\", \"треугольник\"... имеющие похожие методы и свойства \"площадь\" например, но реализуемые по разному для каждого класса. Вполне доходчиво и сразу становится многое понятно)\nВ конце хотел бы отметить, что проблемы сейчас как таковой нет, а топик это просто форма обратной связи, о которой часто просят создатели хекслета. Спасибо. ","topic_id":67791},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":142184,"body":"Спасибо, Виталий! Такая обратная связь действительно очень помогает нам. Проверю, как можно улучшить урок","topic_id":67791}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":62413,"title":"Упорно сбивало с толку то, что присутствует в описании задачи точка. И передаем точку в quadrante. Но ни в каких вычислениях у нас точка не присутствует. Зачем она в задаче?","plain_title":"Упорно сбивало с толку то, что присутствует в описании задачи точка. И передаем точку в quadrante. Но ни в каких вычислениях у нас точка не присутствует. Зачем она в задаче? ","creator":{"public_name":"Игорь Кузнецов","id":422160,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":131713,"body":"Добрый день, Игорь! Точка нужна только как центр геометрической фигуры. В вычислении она действительно никак не участвовала. Немного переделал упражнение, убрал точку, чтобы не вводила в заблуждение. Спасибо!","topic_id":62413}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":87412,"title":"Доброго дня! Я наверное совсем тупой, но я вообще ничего не понял...Полная каша уже в голове. Объясните пожалуйста, что значит \"Внутри интерфейса описываются сигнатуры методов без реализации\"? И непонятно - как один класс может реализовывать несколько интерфейсов если мы при объявлении класса указываем только один интерфейс через implements? Или мы можем по порядку указать несколько? \nЗадания я с горем пополам сделал, просто по теории, но вообще не понял ничего. Зачем мы прописываем класс Quadrate если в вызове метода в классе App мы работаем с интерфейсом, а в интерфейсе описаны методы? Как метод понимает какую фигуру нам нужно? Можете по порядку расписать как происходит вывод площади круга? Куда, какие значения попадают? ","plain_title":"Доброго дня! Я наверное совсем тупой, но я вообще ничего не понял...Полная каша уже в голове. Объясните пожалуйста, что значит \"Внутри интерфейса описываются сигнатуры методов без реализации\"? И непонятно - как один класс может реализовывать несколько интерфейсов если мы при объявлении класса указываем только один интерфейс через implements? Или мы можем по порядку указать несколько? Задания я с горем пополам сделал, просто по теории, но вообще не понял ничего. Зачем мы прописываем класс Quadrate если в вызове метода в классе App мы работаем с интерфейсом, а в интерфейсе описаны методы? Как метод понимает какую фигуру нам нужно? Можете по порядку расписать как происходит вывод площади круга? Куда, какие значения попадают? ","creator":{"public_name":"Pavel Gorobets","id":592280,"is_tutor":false},"comments":[{"creator":{"public_name":"Artur Lastovskiy","id":453210,"is_tutor":false},"id":175852,"body":"Мне кажется в теории самое важное это понят это. \n\n> В коде выше видно, что мы требуем передавать в метод create тип PasswordGenerator. Таким типом будет любой объект, класс которого реализует интерфейс PasswordGenerator.\n\nВ упражнении у нас два класса Quadrate и Circle. И оба реализованы с Geometric интерфейсом. Если так подумать, то без этого нам бы пришлось постоянно определять нужный тип для передачи в App.getFigureSquare(**Quadrate quadrate**) или App.getFigureSquare(**Circle circle**). \n\nА так как типом Geometric будет обладать любой объект, класс которого реализует интерфейс Geometric, то в данном случает это оба класс Quadrate и Circle. Задача упрощается просто указанием App.getFigureSquare(**Geometric параметр**).\n\nА сигнатуры без реализации, так как например площадь круга и квадрата имеют разные формулы вычисления площади. Фактически это очень разные фигуры, но у них есть общее свойство (если так можно сказать) это площадь. \n\nЕсли где-то не прав, прошу поддержку поправить. \n\n","topic_id":87412},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":175908,"body":"Артур, все верно. Завязывая метод `getFigureSquare()` не на конкретный класс, а на интерфейс, мы можем передать туда объект любого класса, который реализует этот интерфейс. Как вы верно заметили, интерфейс содержит только сигнатуру метода, а конкретные реализации содержаться уже в классах, так как реализации могут отличаться","topic_id":87412},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":175210,"body":"Приветствую, Павел! При помощи интерфейса мы описываем только форму, но не реализацию. Именно поэтому в интерфейсе есть только сигнатуры - мы описываем имена методов, списки аргументов, тип возвращаемого значения. Но не реализацию. Те самым мы говорим, что именно так должны выглядеть все классы, которые реализуют интерфейс. Класс может реализовывать множество интерфейсов, нужно указать из через запятую\n\nПосмотрите на пример из задания:\n\n```java\nGeometric quadrate = new Quadrate(5);\nApp.getFigureSquare(quadrate); // \"Square of quadrate is 25\"\n \n// Класс Circle тоже реализует интерфейс Geometric\n// Этот класс уже определён в упражнении\nGeometric circle = new Circle(10);\n// Метод может работать с любым классом, реализующим интерфейс Geometric\nApp.getFigureSquare(circle); // \"Square of circle is 314\"\n```\n\nТак как в методе getFigureSquare() мы работаем с интерфейсом, а не с конкретным классом, то мы можем передать туда любой класс, реализующий интерфейс `Geometric`. Так как метод getFigureSquare() завязан на интерфейс (то есть на форму), он знает что у того, что ему передали обязательно есть метод `int getSquare()`. Он его вызывает и получает площадь фигуры, особо не задумываясь, какой конкретно класс ему передали - круг, квадрат или треугольник","topic_id":87412}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":83246,"title":"Весьма непонятное описание задание в Readme за счет смешения понятий \"реализовать\" ... интерфейс класс... В теоретической части это \"реализовать\" использовано в гораздо более узком смысле, а в задании оно сплошь и рядом вместо \"напишите\", создайте... Может для уже писавшего код по этому разделу это и не создаст трудностей, а новичка это изрядно путает. Пока поймешь, что именно хотел сказать автор, изрядно помучаешься...","plain_title":"Весьма непонятное описание задание в Readme за счет смешения понятий \"реализовать\" ... интерфейс класс... В теоретической части это \"реализовать\" использовано в гораздо более узком смысле, а в задании оно сплошь и рядом вместо \"напишите\", создайте... Может для уже писавшего код по этому разделу это и не создаст трудностей, а новичка это изрядно путает. Пока поймешь, что именно хотел сказать автор, изрядно помучаешься... ","creator":{"public_name":"Alexander Telenkov","id":540740,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":169095,"body":"Приветствую, Александр! Спасибо, поправил формулировки в задании. Нужно будет нажать на Сброс, чтобы получить новую версию упражнения. Не забудьте перед сбросом [сохранить](https://help.hexlet.io/ru/articles/282174-kak-soxranit-svoe-resenie) решение, чтобы не потерять его","topic_id":83246}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":76575,"title":"В примере с генератором паролей в определении метода точка с запятой идет после фигурных скобок, так и должно быть?\n\n\n```\nclass SimplePasswordGenerator implements PasswordGenerator {\n public String generate() {\n // Обращаемся к методу объекта\n // 16 – выбранное значение по умолчанию\n return this.generate(16);\n };\n\n public String generate(int length) {\n // Тут логика генерации пароля\n };\n`}`\n```","plain_title":"В примере с генератором паролей в определении метода точка с запятой идет после фигурных скобок, так и должно быть? class SimplePasswordGenerator implements PasswordGenerator { public String generate() { // Обращаемся к методу объекта // 16 – выбранное значение по умолчанию return this.generate(16); }; public String generate(int length) { // Тут логика генерации пароля }; `}` ","creator":{"public_name":"Рустам Ахмедзянов","id":465342,"is_tutor":false},"comments":[{"creator":{"public_name":"Евгений Прохоров","id":408048,"is_tutor":false},"id":159246,"body":"Добрый вечер, на сколько я знаю, верно и \"}\" и \"};\", компилятор отработает и в том и другом случае корректно.","topic_id":76575},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":159297,"body":"Тут действительно точки с запятой не нужны после определения методов. Спасибо, поправил","topic_id":76575}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":78839,"title":"##### Команда Hexlet, доброго времени суток!\n\nУ меня возникли проблемы с пониманием материала и хочу поделиться мыслями на этот счет.\n\n**Что мне было непонятно**\n\nВ теории нет упоминания про сигнатуру метода в интерфейсе, что это, зачем это и т.д. Но в тестах это определение есть, и это немного сбивает.\n\nТакже не описано правила создания интерфейса, что в нем делать можно и нельзя, почему. \n\n> *Теперь с помощью интерфейса опишем требования к классу генератору. Опишем два метода generate(): один без параметров, другой — с возможностью настройки длины пароля.*\n\nСкладывается впечатление, что интерфейс почему-то нужен для одного класса (в данном случае \"генератоа\"), задавать ему требования, хотя для этого вроде есть переменные, конструкторы, методы и прочие инструменты. От сюда идут ложные и путанные представления, как это должно работать с классом/классами?? и зачем это вообще надо, следовательно получаем проблемы с практикой и \"гуглеж\" других источников.\n\n> *Теперь интерфейс нужно реализовать. Делается это в определении класса: \n`class SimplePasswordGenerator implements PasswordGenerator {`*\n\nНет упоминания про *```implements```* зачем оно нужно и почему интерфейс нужно реализовывать в определении класса (формулировка тоже не самая простая для усвоения)\n\n**Что на мой взгляд было бы понятнее**\n\nДобавить более простой пример из жизни с двумя разными классами/объектами, и на их примере показать как используются интерфейсы. Например:\n- Самолет и бабочка, оба со свойством летать. А если мы захотим бросить кирпич в самолет или бабочку (осуждаю), то и у кирпича это свойство появляется. Но реализация у всех разная.\n- Автосервис, колесо и двигатель. Все это можно чинить, но реализация будет также отличаться, поэтому в интерфейсах определяется только сигнатура метода.\n\nНу и не хватает примера с использованием разных интерфейсов в одном классе. \nНу, как-то так...","plain_title":"Команда Hexlet, доброго времени суток! У меня возникли проблемы с пониманием материала и хочу поделиться мыслями на этот счет. Что мне было непонятно В теории нет упоминания про сигнатуру метода в интерфейсе, что это, зачем это и т.д. Но в тестах это определение есть, и это немного сбивает. Также не описано правила создания интерфейса, что в нем делать можно и нельзя, почему. Теперь с помощью интерфейса опишем требования к классу генератору. Опишем два метода generate(): один без параметров, другой — с возможностью настройки длины пароля. Складывается впечатление, что интерфейс почему-то нужен для одного класса (в данном случае \"генератоа\"), задавать ему требования, хотя для этого вроде есть переменные, конструкторы, методы и прочие инструменты. От сюда идут ложные и путанные представления, как это должно работать с классом/классами?? и зачем это вообще надо, следовательно получаем проблемы с практикой и \"гуглеж\" других источников. Теперь интерфейс нужно реализовать. Делается это в определении класса: class SimplePasswordGenerator implements PasswordGenerator { Нет упоминания про implements зачем оно нужно и почему интерфейс нужно реализовывать в определении класса (формулировка тоже не самая простая для усвоения) Что на мой взгляд было бы понятнее Добавить более простой пример из жизни с двумя разными классами/объектами, и на их примере показать как используются интерфейсы. Например: - Самолет и бабочка, оба со свойством летать. А если мы захотим бросить кирпич в самолет или бабочку (осуждаю), то и у кирпича это свойство появляется. Но реализация у всех разная. - Автосервис, колесо и двигатель. Все это можно чинить, но реализация будет также отличаться, поэтому в интерфейсах определяется только сигнатура метода. Ну и не хватает примера с использованием разных интерфейсов в одном классе. Ну, как-то так... ","creator":{"public_name":"Алексей","id":533722,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":170384,"body":"Добрый день, Алексей! Доработал урок по вашему фидбеку, спасибо! \n\nВ дополнение хочу сказать, что рассказывать ООП на предметах из жизни - не очень хорошее решение, это создает ложное представление. Ведь ООП не моделирует реальный мир, оно моделирует предметную область. А большинство объектов в программах вообще не имеет аналогов в реальном мире. Например, парсеры, логеры и те же генераторы паролей. Обратите внимание, что дальше по программе будет более продвинутый курс по ООП и там мы углубимся в интерфейсы","topic_id":78839},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":162677,"body":"Приветствую, Алексей! Спасибо за подробный фидбек. Посмотрю, как тут можно улучшить урок. Поставил тикет на эту задачу","topic_id":78839}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":71773,"title":"Здравствуйте! Подскажите, где я свернул не туда? https://ru.hexlet.io/code_reviews/661952","plain_title":"Здравствуйте! Подскажите, где я свернул не туда? https://ru.hexlet.io/code_reviews/661952 ","creator":{"public_name":"Илья Остапенко","id":474463,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":150176,"body":"Илья, вы почти у цели, осталось совсем немного поправить. Из метода `getFigureSquare()` нужно вернуть саму строку. Сейчас же возвращается результат вызова метода `System.out.println()`, а этот метод ничего не возвращает, он имеет тип `void`. Поэтому и получается такая ошибка. Верните саму строку из метода","topic_id":71773},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":150082,"body":"Приветствую, Илья! Если какой-то класс реализует интерфейс, то методы этого класса должны иметь точно таку же сигнатуру, как и в интерфейсе. Сейчас в квадрате методы getName() и getSquare() определены корректно, они не принимают параметров. Но методы в интерфейсе Geometric определены так, что они должны принимать параметр. Представьте, должны ли эти методы принимать какие-нибудь параметры? Они же вызываются на экземпляре геометрической фигуры и возвращают имя и площадь этой фигуры","topic_id":71773},{"creator":{"public_name":"Илья Остапенко","id":474463,"is_tutor":false},"id":150116,"body":"**Maksim Litvinov**, Спасибо! Я вас услышал, проанализировал и понял тему лучше. Однако теперь при попытке вывода результата getFigureSquare(), выдается ошибка incompatible types: void cannot be converted to java.lang.String. Пересмотрел весь код, я void не указывал нигде. Он есть только в проверке https://ru.hexlet.io/code_reviews/661952","topic_id":71773},{"creator":{"public_name":"Илья Остапенко","id":474463,"is_tutor":false},"id":150178,"body":"**Maksim Litvinov**, спасибо Вам огромное! Благодаря вашим советам лучше понимаю некоторые темы)","topic_id":71773}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":73920,"title":"Здравствуйте, попрошу направить по возможности:\n\nhttps://ru.hexlet.io/code_reviews/696737\n\nНасколько понимаю, программа показывает, что никак не может завершиться? Только непонятно, почему ","plain_title":"Здравствуйте, попрошу направить по возможности: https://ru.hexlet.io/code_reviews/696737 Насколько понимаю, программа показывает, что никак не может завершиться? Только непонятно, почему ","creator":{"public_name":"Дарья Тараканова","id":445988,"is_tutor":false},"comments":[{"creator":{"public_name":"Дарья Тараканова","id":445988,"is_tutor":false},"id":154240,"body":"Максим, спасибо, пропустила элементарную ошибку из-за невнимательности! ","topic_id":73920},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":154223,"body":"Добрый день, Дарья! Да, все верно. Происходит переполнение стека вызова методов и программа завершается с ошибкой. Давайте посмотрим, что происходит в этой строке кода:\n\n```\npublic int getSquare(){\n return this.getSquare();\n }\n```\n\nМетод getSquare() вызывает сам себя. Представьте, как это будет работать. Метод getSquare() вызывает метод getSquare(), который вызывает метод getSquare(), который ... и так далее, пока стек вызовов не переполнится. Это называется бесконечная [рекурсия](https://ru.wikipedia.org/wiki/Рекурсия#:~:text=Реку́рсия%20—%20определение%2C%20описание%2C%20изображение,объект%20является%20частью%20самого%20себя.)\n\nЕсли у нас есть сторона квадрата, как нам посчитать его площадь?\n","topic_id":73920}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":1638,"slug":"java_oop_basics_interfaces_exercise","name":null,"state":"active","kind":"exercise","language":"java","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"## src/main/java/io/hexlet/Geometric.java\n\nСоздайте интерфейс `Geometric` для работы с геометрическими фигурами. Этот интерфейс имеет два метода:\n\n* `getName()` – возвращает строку, имя геометрической фигуры\n* `getSquare()` – возвращает площадь геометрической фигуры, число типа `double`\n\n## src/main/java/io/hexlet/Quadrate.java\n\nСоздайте класс `Quadrate` который представляет собой квадрат. Класс должен реализовывать интерфейс `Geometric`. Конструктор класса принимает в качестве аргумента сторону квадрата (целое число типа `int`). Так как стороны квадрата равны, для нашей задачи вполне достаточно будет одной стороны, чтобы однозначно определить квадрат\n\nТак как класс реализует интерфейс `Geometric`, вам понадобится определить в нём методы `getName()` и `getSquare()`. Метод `getName()` должен возвращать название фигуры – строку \"quadrate\", а метод `getSquare()` – площадь квадрата.\n\n```java\nGeometric quadrate = new Quadrate(5);\n```\n\n## src/main/java/io/hexlet/App.java\n\nВ классе `App` напишите публичный статический метод `getFigureSquare()`, который принимает в качестве аргумента геометрическую фигуру типа `Geometric`. Метод должен возвращать площадь фигуры в виде строки формата \"Square of quadrate is 36.0\"\n\n```java\nGeometric quadrate = new Quadrate(5);\nApp.getFigureSquare(quadrate); // \"Square of quadrate is 25.0\"\n\n// Класс Circle тоже реализует интерфейс Geometric\n// Этот класс уже определён в упражнении\nGeometric circle = new Circle(10);\n// Метод может работать с любым классом, реализующим интерфейс Geometric\nApp.getFigureSquare(circle); // \"Square of circle is 314.15...\"\n```\n","prepared_readme":"## src/main/java/io/hexlet/Geometric.java\n\nСоздайте интерфейс `Geometric` для работы с геометрическими фигурами. Этот интерфейс имеет два метода:\n\n* `getName()` – возвращает строку, имя геометрической фигуры\n* `getSquare()` – возвращает площадь геометрической фигуры, число типа `double`\n\n## src/main/java/io/hexlet/Quadrate.java\n\nСоздайте класс `Quadrate` который представляет собой квадрат. Класс должен реализовывать интерфейс `Geometric`. Конструктор класса принимает в качестве аргумента сторону квадрата (целое число типа `int`). Так как стороны квадрата равны, для нашей задачи вполне достаточно будет одной стороны, чтобы однозначно определить квадрат\n\nТак как класс реализует интерфейс `Geometric`, вам понадобится определить в нём методы `getName()` и `getSquare()`. Метод `getName()` должен возвращать название фигуры – строку \"quadrate\", а метод `getSquare()` – площадь квадрата.\n\n```java\nGeometric quadrate = new Quadrate(5);\n```\n\n## src/main/java/io/hexlet/App.java\n\nВ классе `App` напишите публичный статический метод `getFigureSquare()`, который принимает в качестве аргумента геометрическую фигуру типа `Geometric`. Метод должен возвращать площадь фигуры в виде строки формата \"Square of quadrate is 36.0\"\n\n```java\nGeometric quadrate = new Quadrate(5);\nApp.getFigureSquare(quadrate); // \"Square of quadrate is 25.0\"\n\n// Класс Circle тоже реализует интерфейс Geometric\n// Этот класс уже определён в упражнении\nGeometric circle = new Circle(10);\n// Метод может работать с любым классом, реализующим интерфейс Geometric\nApp.getFigureSquare(circle); // \"Square of circle is 314.15...\"\n```\n","has_solution":true,"entity_name":"Интерфейсы"},"units":[{"id":5188,"name":"theory","url":"/courses/java-oop-basics/lessons/interfaces/theory_unit"},{"id":5421,"name":"quiz","url":"/courses/java-oop-basics/lessons/interfaces/quiz_unit"},{"id":5283,"name":"exercise","url":"/courses/java-oop-basics/lessons/interfaces/exercise_unit"}],"links":[{"id":425693,"name":"Интерфейсы. Официальная документация","url":"https://docs.oracle.com/javase/tutorial/java/concepts/interface.html\n"}],"ordered_units":[{"id":5188,"name":"theory","url":"/courses/java-oop-basics/lessons/interfaces/theory_unit"},{"id":5421,"name":"quiz","url":"/courses/java-oop-basics/lessons/interfaces/quiz_unit"},{"id":5283,"name":"exercise","url":"/courses/java-oop-basics/lessons/interfaces/exercise_unit"}],"id":2354,"slug":"interfaces","state":"approved","name":"Интерфейсы","course_order":800,"goal":"Знакомимся с концепцией интерфейсов, которые ведут нас к светлому полиморфизму","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"\n\nКлассы в Java — основы основ, но их описание будет неполным без интерфейсов, с которыми они тесно связаны. Интерфейсы — более простая конструкция, но, как и в случае с классами, полное понимание интерфейсов требует опыта работы с ними. Зачем они нужны? Интерфейсы позволяют задавать требования к классам, то есть какие методы требуются от класса. Предположим, что мы хотим работать в приложении с генератором паролей. Генератор в нашем случае это обычный класс, с методом `generate()`, возвращающим пароль.\n\n```java\nvar generator = new SimplePasswordGenerator();\ngenerator.generate(); // Возвращает готовый пароль\ngenerator.generate(); // Уже другой пароль\n```\n\nТеперь с помощью интерфейса опишем требования к классу генератора. Задача интерфейса — определить функционал, который затем будет реализован классами. Поэтому интерфейс содержит только сигнатуру методов без их реализации.\n\nСоздадим интерфейс `PasswordGenerator` и опишем в нем два метода `generate()`. Один метод будет без параметров, другой — с возможностью настройки длины пароля:\n\n```java\ninterface PasswordGenerator {\n String generate();\n String generate(int length);\n}\n```\n\nТеперь интерфейс нужно **реализовать**. Делается это в определении класса:\n\n```java\n// Ключевое слово implements означает, что класс реализует интерфейс PasswordGenerator\nclass SimplePasswordGenerator implements PasswordGenerator {\n public String generate() {\n // Обращаемся к методу объекта\n // 16 – выбранное значение по умолчанию\n return this.generate(16);\n }\n\n public String generate(int length) {\n // Тут логика генерации простого пароля\n }\n}\n```\n\nИнтерфейсы не ограничивают класс в его расширении. Помимо интерфейсных методов, мы можем добавить и любые другие.\n\nНо все таки одно ограничение есть. Если класс применяет интерфейс, то он должен реализовывать все методы, указанные в интерфейсе, причем именно так, как они описаны.\n\nВ чем же суть интерфейсов? Если коротко: полиморфизм, а если точнее — полиморфизм подтипов ([subtyping](https://en.wikipedia.org/wiki/Subtyping)). Прямо сейчас он нам не очень нужен, но для общего развития попробуем ухватить его идею.\n\n*Осторожно, дальнейший текст может напугать. Если он кажется вам сложным, просто пропустите, все это мы будем повторять еще не раз.*\n\nКод, который будет использовать `passwordGenerator` может выглядеть так:\n\n```java\nclass UserController {\n // Здесь создаются пользователи\n // Этот код вызывается где-то внутри приложения при регистрации пользователя\n public void create() {\n // Создаем пользователя\n // И где-то тут же генерируем ему пароль\n var generator = new SimplePasswordGenerator();\n var password = generator.generate();\n }\n}\n```\n\nНеплохой код, но представьте, что класс может меняться без изменения кода, просто в зависимости от того, какие опции выбирает пользователь при генерации пароля. Вполне реальная ситуация. Самый простой способ реализовать такую схему — вставить условие на параметр, который вводит пользователь. В одном случае берем один класс, в другом другой.\n\n```java\nvar generator;\nif (userChooseSomething) {\n generator = new SimplePasswordGenerator();\n} else {\n generator = new SuperPasswordGenerator();\n}\n```\n\nТакой код уже может стать проблемой, если генераторы будут постоянно добавляться. Ситуация ухудшится, когда эта конструкция начнет расползаться по разным частям проекта. Интерфейсы изящно решают такие ситуации.\n\nСделаем так, чтобы класс `SuperPasswordGenerator()` тоже реализовывал интерфейс `PasswordGenerator`:\n\n```java\nclass SuperPasswordGenerator implements PasswordGenerator {\n public String generate() {\n return this.generate(16);\n }\n\n public String generate(int length) {\n // Тут уже другая логика генерации супер-сложного пароля\n }\n}\n```\n\nКод, который будет использовать `PasswordGenerator`, меняется на такой:\n\n```java\nclass UserController {\n // Интерфейс = Тип\n // Вместо конкретного класса указываем интерфейс\n public void create(PasswordGenerator generator) {\n var password = generator.generate();\n }\n}\n```\n\nИнтерфейсы в Java — это настоящие типы данных, поэтому их можно указывать в определениях методов.\n\nВ коде выше видно, что мы требуем передавать в метод `create` тип `PasswordGenerator`. Таким типом будет любой объект, класс которого реализует интерфейс `PasswordGenerator`. Теперь мы можем передать в метод `create()` любой генератор паролей, который реализует интерфейс `PasswordGenerator`. В получившемся коде генератор создается не там, где используется. Он создается где-то раньше, а уже в код приходит нужная реализация.\n\nТаким образом мы можем получить разное поведение, не меняя сам код, который использует `PasswordGenerator`.\n\nВсе это уже станет актуальным, как только мы дойдем до Java-коллекций.\n\n## Соглашения и правила\n\nК интерфейсам предъявляются такие же требования как и к классам\n\n1. Один файл – один интерфейс. Имя файла и интерфейса совпадают.\n1. Интерфейсы начинаются с заглавной буквы.\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":5181,"name":"theory","url":"/courses/java-oop-basics/lessons/about/theory_unit"}],"links":[],"ordered_units":[{"id":5181,"name":"theory","url":"/courses/java-oop-basics/lessons/about/theory_unit"}],"id":2347,"slug":"about","state":"approved","name":"О курсе","course_order":100,"goal":"Знакомимся с целями и задачами курса","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Классы в Java одна из ключевых концепций, вокруг которой строится код. Буквально весь код описывается внутри классов без возможности выбора. Этим Java сильно отличается от многих других языков, где классы добавляются только по необходимости либо их нет вообще.\n\nЧтобы понять классы по-настоящему, нужно время и опыт, но из-за их глубокой интеграции в код, нам приходится разбирать их буквально в самом начале обучения. Чтобы сделать этот процесс легче, изучение классов и сопутствующих элементов разделено на две части. В одной, прямо здесь мы поговорим лишь о самых основах, которых достаточно для изучения ближайшего материала и создания полноценных программ. В другой, там где идет разбор объектно-ориентированного программирования, мы погрузимся в классы по полной программе. К тому моменту у вас будет достаточно опыта для понимания материала.\n\nВ этом курсе мы научимся создавать объекты и работать с ними. Познакомимся с базовыми принципами создания классов, добавим геттеры и сеттеры. Введем интерфейсы и разобьем код по пакетам.\n"},"id":256,"slug":"java-oop-basics","challenges_count":5,"name":"Java: Введение в ООП","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы изучите основы объектно-ориентированного программирования. Вы познакомитесь с классами, объектами и методами — этими понятиями оперирует любая Java-программа. Здесь вы узнаете об интерфейсах и пакетах, в итоге научитесь описывать классы, создавать объекты, вызывать их методы и группировать классы в своем коде. Объектно-ориентированное программирование в Java начинается с первых строчек кода. В этом курсе вы получите необходимые базовые навыки программирования в ООП-стиле.","kind":"basic","updated_at":"2026-01-20T11:55:17.291Z","language":"java","duration_cache":48480,"skills":["Описывать сущности предметной области с помощью классов","Создавать объекты и вызывать их методы","Задавать требования к классам при помощи интерфейсов","Группировать классы при помощи пакетов"],"keywords":[],"lessons_count":11,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTIzMSwicHVyIjoiYmxvYl9pZCJ9fQ==--8ed815c1a448dabbcc1c22f6d8d6f53675ce6bee/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJqcGciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--39ba06fa99226096df9fc6bb31f84e1d29ea98e9/image.png"},"recommendedLandings":[{"stack":{"id":3,"slug":"java","title":"Java-разработчик","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":30,"duration_in_months":10},"id":3,"slug":"java","title":"Java-разработчик","subtitle":"Изучите Java и фреймворк Spring Boot и REST API","subtitle_for_lists":"Изучите Java и фреймворк Spring Boot и REST API","locale":"ru","current":true,"duration_in_months_text":"10 месяцев","stack_slug":"java","price_text":"от 6 792 ₽","duration_text":"10 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzczNSwicHVyIjoiYmxvYl9pZCJ9fQ==--883f3fd4e1b571538035b5680c8d4a9eb504b1f6/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Source%20code-amico.png"},{"stack":{"id":219,"slug":"qa-auto-engineer-java","title":"Автоматизатор тестирования на Java","audience":"for_programmers","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":110,"duration_in_months":6},"id":329,"slug":"qa-auto-engineer-java","title":"Автоматизатор тестирования на Java","subtitle":"Изучите Java и фреймворк для UI- и API-автотестов","subtitle_for_lists":"Изучите Java и фреймворк для UI- и API-автотестов","locale":"ru","current":true,"duration_in_months_text":"6 месяцев","stack_slug":"qa-auto-engineer-java","price_text":"от 4 281 ₽","duration_text":"6 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzkyMywicHVyIjoiYmxvYl9pZCJ9fQ==--da8237868b3f1c36e3fe891b47b4869fa9f2e8ef/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Bug%20fixing-pana.png"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/java-oop-basics/lessons/interfaces/theory_unit","version":"0b0c6d4ebbd40fd58630a0dd89cc25544ccdf24e","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Java: Введение в ООП</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Интерфейсы</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Интерфейсы","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"Java: Введение в ООП"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTI0MCwicHVyIjoiYmxvYl9pZCJ9fQ==--12c7df67ea02700173ecd65099a0c0e49bf78a8f/01.png" alt="Интерфейсы" loading="lazy"/></p>
<p>Классы в Java — основы основ, но их описание будет неполным без интерфейсов, с которыми они тесно связаны. Интерфейсы — более простая конструкция, но, как и в случае с классами, полное понимание интерфейсов требует опыта работы с ними. Зачем они нужны? Интерфейсы позволяют задавать требования к классам, то есть какие методы требуются от класса. Предположим, что мы хотим работать в приложении с генератором паролей. Генератор в нашем случае это обычный класс, с методом <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">generate()</code>, возвращающим пароль.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">var generator = new SimplePasswordGenerator();
generator.generate(); // Возвращает готовый пароль
generator.generate(); // Уже другой пароль</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Теперь с помощью интерфейса опишем требования к классу генератора. Задача интерфейса — определить функционал, который затем будет реализован классами. Поэтому интерфейс содержит только сигнатуру методов без их реализации.</p>
<p>Создадим интерфейс <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">PasswordGenerator</code> и опишем в нем два метода <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">generate()</code>. Один метод будет без параметров, другой — с возможностью настройки длины пароля:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">interface PasswordGenerator {
String generate();
String generate(int length);
}</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Теперь интерфейс нужно <strong>реализовать</strong>. Делается это в определении класса:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">// Ключевое слово implements означает, что класс реализует интерфейс PasswordGenerator
class SimplePasswordGenerator implements PasswordGenerator {
public String generate() {
// Обращаемся к методу объекта
// 16 – выбранное значение по умолчанию
return this.generate(16);
}
public String generate(int length) {
// Тут логика генерации простого пароля
}
}</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Интерфейсы не ограничивают класс в его расширении. Помимо интерфейсных методов, мы можем добавить и любые другие.</p>
<p>Но все таки одно ограничение есть. Если класс применяет интерфейс, то он должен реализовывать все методы, указанные в интерфейсе, причем именно так, как они описаны.</p>
<p>В чем же суть интерфейсов? Если коротко: полиморфизм, а если точнее — полиморфизм подтипов (<a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://en.wikipedia.org/wiki/Subtyping" rel="noopener noreferrer" target="_blank">subtyping</a>). Прямо сейчас он нам не очень нужен, но для общего развития попробуем ухватить его идею.</p>
<p><em>Осторожно, дальнейший текст может напугать. Если он кажется вам сложным, просто пропустите, все это мы будем повторять еще не раз.</em></p>
<p>Код, который будет использовать <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">passwordGenerator</code> может выглядеть так:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">class UserController {
// Здесь создаются пользователи
// Этот код вызывается где-то внутри приложения при регистрации пользователя
public void create() {
// Создаем пользователя
// И где-то тут же генерируем ему пароль
var generator = new SimplePasswordGenerator();
var password = generator.generate();
}
}</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Неплохой код, но представьте, что класс может меняться без изменения кода, просто в зависимости от того, какие опции выбирает пользователь при генерации пароля. Вполне реальная ситуация. Самый простой способ реализовать такую схему — вставить условие на параметр, который вводит пользователь. В одном случае берем один класс, в другом другой.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">var generator;
if (userChooseSomething) {
generator = new SimplePasswordGenerator();
} else {
generator = new SuperPasswordGenerator();
}</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Такой код уже может стать проблемой, если генераторы будут постоянно добавляться. Ситуация ухудшится, когда эта конструкция начнет расползаться по разным частям проекта. Интерфейсы изящно решают такие ситуации.</p>
<p>Сделаем так, чтобы класс <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">SuperPasswordGenerator()</code> тоже реализовывал интерфейс <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">PasswordGenerator</code>:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">class SuperPasswordGenerator implements PasswordGenerator {
public String generate() {
return this.generate(16);
}
public String generate(int length) {
// Тут уже другая логика генерации супер-сложного пароля
}
}</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Код, который будет использовать <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">PasswordGenerator</code>, меняется на такой:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">class UserController {
// Интерфейс = Тип
// Вместо конкретного класса указываем интерфейс
public void create(PasswordGenerator generator) {
var password = generator.generate();
}
}</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Интерфейсы в Java — это настоящие типы данных, поэтому их можно указывать в определениях методов.</p>
<p>В коде выше видно, что мы требуем передавать в метод <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">create</code> тип <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">PasswordGenerator</code>. Таким типом будет любой объект, класс которого реализует интерфейс <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">PasswordGenerator</code>. Теперь мы можем передать в метод <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">create()</code> любой генератор паролей, который реализует интерфейс <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">PasswordGenerator</code>. В получившемся коде генератор создается не там, где используется. Он создается где-то раньше, а уже в код приходит нужная реализация.</p>
<p>Таким образом мы можем получить разное поведение, не меняя сам код, который использует <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">PasswordGenerator</code>.</p>
<p>Все это уже станет актуальным, как только мы дойдем до Java-коллекций.</p>
<h2 id="heading-2-1">Соглашения и правила</h2>
<p>К интерфейсам предъявляются такие же требования как и к классам</p>
<ol>
<li>Один файл – один интерфейс. Имя файла и интерфейса совпадают.</li>
<li>Интерфейсы начинаются с заглавной буквы.</li>
</ol></div><div style="margin-block:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Рекомендуемые программы</h2><style data-mantine-styles="inline">.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_2mremqrdub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/java?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Java-разработчик</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите Java и фреймворк Spring Boot и REST API</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzczNSwicHVyIjoiYmxvYl9pZCJ9fQ==--883f3fd4e1b571538035b5680c8d4a9eb504b1f6/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Source%20code-amico.png" alt="Java-разработчик" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 6 792 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/qa-auto-engineer-java?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">6 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Автоматизатор тестирования на Java</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите Java и фреймворк для UI- и API-автотестов</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzkyMywicHVyIjoiYmxvYl9pZCJ9fQ==--da8237868b3f1c36e3fe891b47b4869fa9f2e8ef/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Bug%20fixing-pana.png" alt="Автоматизатор тестирования на Java" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 4 281 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h3)" class="m_8a5d1357 mantine-Title-root" data-order="2" data-responsive="true">Каталог</h2><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Полный список доступных курсов по разным направлениям</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="/vite/assets/development-BVihs_d5.png" alt="Orientation"/></div></div></div></a></div></div></div></div></div></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/java-oop-basics/lessons/interfaces/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 11</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/java-oop-basics/lessons/interfaces/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-CdBlNCiQ.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>