major: remade 01,02 to direct svg usage, done sem01, made hw for sem02, minor started a04, edits in a03

This commit is contained in:
Ivan I. Ovchinnikov 2022-12-18 00:05:43 +03:00
parent ab2d8730ca
commit 81602e494b
17 changed files with 1283 additions and 338 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,6 @@
\documentclass[j-spec.tex]{subfiles}
\begin{document}
\pagestyle{plain}
\sloppy
\tableofcontents
\section{Платформа: история и окружение}
\subsection{В этом разделе}
@ -14,14 +12,14 @@
\item \nom{JRE}{(от англ. Java Runtime Environment) — минимальная (без компилятора и других средств разработки) реализация виртуальной машины, необходимая для исполнения Java-приложений. Состоит из виртуальной машины Java Virtual Machine и библиотеки Java-классов.}
\item \nom{JVM}{(от англ. Java Virtual Machine) — виртуальная машина Java, основная часть исполняющей системы Java. Виртуальная машина Java исполняет байт-код, предварительно созданный из исходного текста Java-программы компилятором. JVM может также использоваться для выполнения программ, написанных на других языках программирования.}
\item \nom{JIT}{(англ. Just-in-Time, компиляция «точно в нужное время»), динамическая компиляция — технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы. Таким образом достигается высокая скорость выполнения по сравнению с интерпретируемым байт-кодом за счёт увеличения потребления памяти (для хранения результатов компиляции) и затрат времени на компиляцию. Технология JIT базируется на двух более ранних идеях, касающихся среды выполнения: компиляции байт-кода и динамической компиляции.}
\item \nom{CLI}{(англ. Command Line Interface, Интерфейс командной строки) — разновидность текстового интерфейса между человеком и компьютером, в котором инструкции компьютеру даются в основном путём ввода с клавиатуры текстовых строк (команд). Также известен под названиями «консоль» и «терминал».}
\item \nom{CLI}{(англ. Command line interface, Интерфейс командной строки) — разновидность текстового интерфейса между человеком и компьютером, в котором инструкции компьютеру даются в основном путём ввода с клавиатуры текстовых строк (команд). Также известен под названиями «консоль» и «терминал».}
\item \nom{Docker}{программное обеспечение для автоматизации развёртывания и управления приложениями, контейнеризатор приложений. Позволяет «упаковать» приложение со всем его окружением и зависимостями в контейнер, который может быть развёрнут почти на любой системе.}
\end{itemize}
\nomenclature{GPL}{GNU General Public License (чаще всего переводят как Открытое лицензионное соглашение GNU) — лицензия на свободное программное обеспечение, созданная в рамках проекта GNU, по которой автор передаёт программное обеспечение в общественную собственность. Её также сокращённо называют GNU GPL или даже просто GPL, если из контекста понятно, что речь идёт именно о данной лицензии. GNU Lesser General Public License (LGPL) — это ослабленная версия GPL, предназначенная для некоторых библиотек ПО.}
\subsection{Краткая история (причины возникновения)}
\begin{itemize}
\item Язык создавали для разработки встраиваемых систем, сетевых приложений и прикладного \nom{ПО}{(программное обеспечение) -- программа или множество программ, используемых для управления компьютером.};
\item Язык создавали для разработки встраиваемых систем, сетевых приложений и прикладного \nom{ПО}{программное обеспечение};
\item Популярен из-за скорости исполнения и полного абстрагирования от исполнителя кода;
\item Часто используется для программирования бэк-энда веб-приложений из-за изначальной нацеленности на сетевые приложения.
\end{itemize}
@ -44,10 +42,10 @@
\subsection{Базовый инструментарий, который понадобится (выбор IDE)}
\begin{itemize}
\item NetBeans -- хороший, добротный инструмент с лёгким ностальгическим оттенком;
\item Eclipse -- для поклонников Eclipse Foundation и швейцарских ножей с полусотней лезвий;
\item IntelliJ IDEA -- стандарт де-факто, используется на курсе и в большинстве современных компаний;
\item Android Studio -- если заниматься мобильной разработкой.
\item NetBeans - хороший, добротный инструмент с лёгким ностальгическим оттенком;
\item Eclipse - для поклонников Eclipse Foundation и швейцарских ножей с полусотней лезвий;
\item IntelliJ IDEA - стандарт де-факто, используется на курсе и в большинстве современных компаний;
\item Android Studio - если заниматься мобильной разработкой.
\end{itemize}
\subsubsection{Задания для самопроверки}
@ -66,7 +64,7 @@
В последнее время, с развитием контейнеризации приложений, часто устанавливают инструментарий в Docker-контейнер и ведут разработку прямо в контейнере, это позволяет не захламлять компьютер разработчика разными версиями инструментария и быстро разворачивать свои приложения в \nom{CI}{(англ. Continious Integration) практика разработки программного обеспечения, которая заключается в постоянном слиянии рабочих копий в общую основную ветвь разработки и выполнении частых автоматизированных сборок проекта для скорейшего выявления потенциальных дефектов и решения интеграционных проблем.} или на целевом сервере.
\begin{frm}
\info В общем случае, для разработки на любом языке программирования нужны так называемые \nom{SDK}{(от англ. software development kit, комплект для разработки программного обеспечения) — это набор инструментов для разработки программного обеспечения в одном устанавливаемом пакете. Они облегчают создание приложений, имея компилятор, отладчик и иногда программную среду. В основном они зависят от комбинации аппаратной платформы компьютера и операционной системы.} (Software Development Kit, англ. -- инструментарий разработчика приложений или инструментарий для разработки приложений). Частный случай такого SDK -- инструментарий разработчика на языке Java -- Java Development Kit.
\info В общем случае, для разработки на любом языке программирования нужны так называемые \nom{SDK}{(от англ. software development kit, комплект для разработки программного обеспечения) — это набор инструментов для разработки программного обеспечения в одном устанавливаемом пакете. Они облегчают создание приложений, имея компилятор, отладчик и иногда программную среду. В основном они зависят от комбинации аппаратной платформы компьютера и операционной системы.} (Software Development Kit, англ. - инструментарий разработчика приложений или инструментарий для разработки приложений). Частный случай такого SDK - инструментарий разработчика на языке Java - Java Development Kit.
\end{frm}
На курсе будет использоваться BellSoft Liberica JDK 11, но возможно использовать и других производителей, например, самую распространённую Oracle JDK. Производителя следует выбирать из требований по лицензированию, так, например, Oracle JDK можно использовать бесплатно только в личных целях, за коммерческую разработку с использованием этого инструментария придётся заплатить.
@ -104,7 +102,7 @@ TL;DR:
Как именно всё работает? Если коротко, то слой за слоем накладывая абстракции. Программы на любом языке программирования исполняются на компьютере, то есть, так или иначе, задействуют процессор, оперативную память и прочие аппаратурные компоненты. Эти аппаратурные компоненты предоставляют для доступа к себе низкоуровневые интерфейсы, которые задействует операционная система, предоставляя в свою очередь интерфейс чуть проще программам, взаимодействующим с ней. Этот интерфейс взаимодействия с \nom{ОС}{(операционная система) — комплекс управляющих и обрабатывающих программ, которые, с одной стороны, выступают как интерфейс между устройствами вычислительной системы и прикладными программами, а с другой стороны — предназначены для управления устройствами, управления вычислительными процессами, эффективного распределения вычислительных ресурсов между вычислительными процессами и организации надёжных вычислений.} мы для простоты будем называть Native API.
С ОС взаимодействует JVM (\href{https://ru.m.wikipedia.org/wiki/Список_виртуальных_машин_Java}{Wikipedia: Список виртуальных машин Java}), то есть, используя Native API, нам становится всё равно, какая именно ОС установлена на компьютере, главное уметь выполняться на JVM. Это открывает простор для создания целой группы языков, они носят общее бытовое название JVM-языки, к ним относят Scala, Groovy, Kotlin и другие. Внутри JVM осуществляется управление памятью, существует механизм исполнения программ, специальный JIT\footnote{JIT, just-in-time -- англ. в\'{о}время, прямо сейчас}-компилятор, генерирующий платформенно-зависимый код.
С ОС взаимодействует JVM (\href{https://ru.m.wikipedia.org/wiki/Список_виртуальных_машин_Java}{Wikipedia: Список виртуальных машин Java}), то есть, используя Native API, нам становится всё равно, какая именно ОС установлена на компьютере, главное уметь выполняться на JVM. Это открывает простор для создания целой группы языков, они носят общее бытовое название JVM-языки, к ним относят Scala, Groovy, Kotlin и другие. Внутри JVM осуществляется управление памятью, существует механизм исполнения программ, специальный JIT\footnote{JIT, just-in-time - англ. в\'{о}время, прямо сейчас}-компилятор, генерирующий платформенно-зависимый код.
JVM для своей работы запрашивает у ОС некоторый сегмент оперативной памяти, в котором хранит данные программы. Это хранение происходит «слоями»:
\begin{enumerate}
@ -112,20 +110,19 @@ JVM для своей работы запрашивает у ОС некотор
\item Survivor Space (heap) сюда перемещаются объекты из предыдущей области после того, как они пережили хотя бы одну сборку мусора. Время от времени долгоживущие объекты из этой области перемещаются в Tenured Space.
\item Tenured (Old) Generation (heap) — Здесь скапливаются долгоживущие объекты (крупные высокоуровневые объекты, синглтоны, менеджеры ресурсов и прочие). Когда заполняется эта область, выполняется полная сборка мусора (full, major collection), которая обрабатывает все созданные JVM объекты.
\item Permanent Generation (non-heap) Здесь хранится метаинформация, используемая JVM (используемые классы, методы и т.п.).
\item Code Cache (non-heap) — эта область используется JVM, когда включена JIT-компиляция, в ней кэшируется скомпилированный платформенно-зависимый код.
\item Code Cache (non-heap) — эта область используется JVM, когда включена JIT-компиляция, в ней кешируется скомпилированный платформенно-зависимый код.
\end{enumerate}
JVM самостоятельно осуществляет сборку так называемого мусора, что значительно облегчает работу программиста по отслеживанию утечек памяти, но важно помнить, что в Java утечки памяти всё равно существуют, особенно при программировании многопоточных приложений.
\begin{figure}[H]
\centering
\def\svgwidth{150mm}
\includesvg{pics/jc-01-jvm-struct.svg}
\caption{Принцип работы JVM}
\includesvg[scale=.9]{pics/jc-01-jvm-struct.svg}
\label{jvm:structure}
\caption{Принцип работы JVM}
\end{figure}
На пользовательском уровне важно не только исполнять базовые инструкции программы, но чтобы эти базовые инструкции умели как-то взаимодействовать со внешним миром, в том числе другими программами, поэтому JVM интегрирована в JRE -- Java Runtime Environment. JRE -- это набор из классов и интерфейсов, реализующих
На пользовательском уровне важно не только исполнять базовые инструкции программы, но чтобы эти базовые инструкции умели как-то взаимодействовать со внешним миром, в том числе другими программами, поэтому JVM интегрирована в JRE - Java Runtime Environment. JRE - это набор из классов и интерфейсов, реализующих
\begin{itemize}
\item возможности сетевого взаимодействия;
\item рисование графики и графический пользовательский интерфейс;
@ -136,7 +133,7 @@ JVM самостоятельно осуществляет сборку так н
\item ... многое другое.
\end{itemize}
Java Development Kit является изрядно дополненным специальными Java приложениями SDK. JDK дополняет JRE не только утилитами для компиляции, но и утилитами для создания документации, отладки, развёртывания приложений и многими другими. В таблице \hrf{table:jdk-contents} на странице \pageref{table:jdk-contents}, приведена примерная структура и состав JDK и JRE, а также указаны их основные и наиболее часто используемые компоненты из состава Java Standard Edition. Помимо стандартной редакции существует и Enterprise Edition, содержащий компоненты для создания веб-приложений, но JEE активно вытесняется фреймворками Spring и Spring Boot.
Java Development Kit является изрядно дополненным специальными Java приложениями SDK. JDK дополняет JRE не только утилитами для компиляции, но и утилитами для создания документации, отладки, развёртывания приложений и многими другими. В таблице \ref{table:jdk-contents} на странице \pageref{table:jdk-contents}, приведена примерная структура и состав JDK и JRE, а также указаны их основные и наиболее часто используемые компоненты из состава Java Standard Edition. Помимо стандартной редакции существует и Enterprise Edition, содержащий компоненты для создания веб-приложений, но JEE активно вытесняется фреймворками Spring и Spring Boot.
\begin{table}[H]
\centering
@ -160,13 +157,13 @@ Java Development Kit является изрядно дополненным сп
& \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{JVM} & \multicolumn{7}{l|}{Java Hot Spot VM (JIT)} \\ \hline
\end{tabular}
\end{adjustbox}
\caption{Общее представление состава JDK}
\label{table:jdk-contents}
\caption{Общее представление состава JDK}
\end{table}
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item JVM и JRE -- это одно и тоже?
\item JVM и JRE - это одно и тоже?
\item Что входит в состав JDK, но не входят в состав JRE?
\item Утечки памяти
\begin{itemize}
@ -201,13 +198,13 @@ public class Main {
\textbf{Обычный проект} состоит из пакетов, которые содержат классы, которые в свою очередь как-то связаны между собой и содержат код, который исполняется.
\begin{itemize}
\item Пакеты. Пакеты объединяют классы по смыслу. Классы, находящиеся в одном пакете доступны друг другу даже если находятся в разных проектах. У пакетов есть правила именования: обычно это обратное доменное имя (например, для gb.ru это будет ru.gb), название проекта, и далее уже внутренняя структура. Пакеты именуют строчными латинскими буквами. Чтобы явно отнести класс к пакету, нужно прописать в классе название пакета после оператора \code{package}.
\item Классы. Основная единица исходного кода программы. Одному файлу следует сопоставлять один класс. Название класса -- это имя существительное в именительном падеже, написанное с заглавной буквы. Если требуется назвать класс в несколько слов, применяют UpperCamelCase.
\item Классы. Основная единица исходного кода программы. Одному файлу следует сопоставлять один класс. Название класса - это имя существительное в именительном падеже, написанное с заглавной буквы. Если требуется назвать класс в несколько слов, применяют UpperCamelCase.
\item \code{public static void main(String[] args)}. Метод, который является точкой входа в программу. Должен находиться в публичном классе. При создании этого метода важно полностью повторить его сигнатуру и обязательно написать его с название со строчной буквы.
\item Комментарии. Это часть кода, которую игнорирует компилятор при преобразовании исходного кода. Комментарии бывают:
\begin{itemize}
\item \code{// comment} -- до конца строки. Самый простой и самый часто используемый комментарий.
\item \code{/* comment */} -- внутристрочный или многострочный. Никогда не используйте его внутри строк, несмотря на то, что это возможно.
\item \code{/** comment */} -- комментарий-документация. Многострочный. Из него утилитой Javadoc создаётся веб-страница с комментарием.
\item \code{// comment} - до конца строки. Самый простой и самый часто используемый комментарий.
\item \code{/* comment */} - внутристрочный или многострочный. Никогда не используйте его внутри строк, несмотря на то, что это возможно.
\item \code{/** comment */} - комментарий-документация. Многострочный. Из него утилитой Javadoc создаётся веб-страница с комментарием.
\end{itemize}
\end{itemize}
@ -246,8 +243,8 @@ public class Main {
[README.md]
]
\end{forest}
\caption{Структура простого проекта}
\label{pic:simple-tree}
\caption{Структура простого проекта}
\end{figure}
Содержимое файлов исходного кода представлено ниже.
@ -309,7 +306,7 @@ Hello, world!
\end{lstlisting}
\begin{frm}
\info Скомпилированные классы всегда содержат одинаковые первые четыре байта, которые в шестнадцатеричном представлении формируют надпись «кофе, крошка».
\info Скомпилированные классы всегда содержат одинаковые первые четыре байта, которые в шестнадцатиричном представлении формируют надпись «кофе, крошка».
\begin{figure}[H]
\centering
\includegraphics[width=14cm]{jc-01-cafe-babe.png}
@ -356,7 +353,7 @@ Here is your number: 4.
\centering
\includegraphics[width=12cm]{jc-01-javadoc.png}
\caption{Часть cтраницы автосгенерированной документации}
\label{pic:}
\label{pic:autodoc}
\end{figure}
Чтобы просто создать документацию надо вызвать утилиту javadoc с набором ключей.
@ -368,7 +365,7 @@ Here is your number: 4.
\item \code{-subpackages} нужно ли заглядывать в пакеты-с-пакетами;
\end{itemize}
Часто необходимо указать, в какой кодировке записан файл исходных кодов, и в какой кодировке должна быть выполнена документация (например, файлы исходников на языке Java всегда сохраняются в кодировке \nom{UTF-8}{(от англ. Unicode Transformation Format, 8-bit — «формат преобразования Юникода, 8-бит») — распространённый стандарт кодирования символов, позволяющий более компактно хранить и передавать символы Юникода, используя переменное количество байт (от 1 до 4), и обеспечивающий полную обратную совместимость с 7-битной кодировкой ASCII. Кодировка UTF-8 сейчас является доминирующей в веб-пространстве. Она также нашла широкое применение в UNIX-подобных операционных системах.}, а основная кодировка для ОС Windows -- \nom{cp1251}{набор символов и кодировка, являющаяся стандартной 8-битной кодировкой для русских версий Microsoft Windows до 10-й версии. Была создана на базе кодировок, использовавшихся в ранних русификаторах Windows.})
Часто необходимо указать, в какой кодировке записан файл исходных кодов, и в какой кодировке должна быть выполнена документация (например, файлы исходников на языке Java всегда сохраняются в кодировке \nom{UTF-8}{(от англ. Unicode Transformation Format, 8-bit — «формат преобразования Юникода, 8-бит») — распространённый стандарт кодирования символов, позволяющий более компактно хранить и передавать символы Юникода, используя переменное количество байт (от 1 до 4), и обеспечивающий полную обратную совместимость с 7-битной кодировкой ASCII. Кодировка UTF-8 сейчас является доминирующей в веб-пространстве. Она также нашла широкое применение в UNIX-подобных операционных системах.}, а основная кодировка для ОС Windows - \nom{cp1251}{набор символов и кодировка, являющаяся стандартной 8-битной кодировкой для русских версий Microsoft Windows до 10-й версии. Была создана на базе кодировок, использовавшихся в ранних русификаторах Windows.})
\begin{itemize}
\item \code{-locale ru_RU} язык документации (для правильной расстановки переносов и разделяющих знаков);
\item \code{-encoding} кодировка исходных текстов программы;
@ -446,12 +443,12 @@ Docker также не привносит ничего технологичес
RUN mkdir ./out
\end{lstlisting}
Последнее, что будет сделано при создании образа -- запущена компиляция.
Последнее, что будет сделано при создании образа - запущена компиляция.
\begin{lstlisting}[style=ASMStyle]
RUN javac -sourcepath ./src -d out ./src/ru/gb/dj/Main.java
\end{lstlisting}
Последняя команда в \code{Dockerfile} говорит, что нужно сделать, когда контейнер создаётся из образа и запускается.
Последняя команда в \code{Dockerfile} говорит, что нужно сделать, когда контейнер создаётся из образа и заускается.
\begin{lstlisting}[style=ASMStyle]
CMD java -classpath ./out ru.gb.dj.Main
\end{lstlisting}
@ -460,15 +457,14 @@ Docker-образ и, как следствие, Docker-контейнеры в
Часто команды разработчиков эмулируют таким образом реальный продакшн сервер, используя в качестве исходного образа не JDK, а образ целевой ОС, вручную устанавливают на ней JDK, запуская далее своё приложение.
\subsection*{Практическое задание}
\subsection*{Домашнее задание}
\begin{itemize}
\item Создать проект из трёх классов (основной с точкой входа и два класса в другом пакете), которые вместе должны составлять одну программу, позволяющую производить четыре основных математических действия и осуществлять форматированный вывод результатов пользователю;
\item Скомпилировать проект, а также создать для этого проекта стандартную веб-страницу с документацией ко всем пакетам;
\item Создать Makefile с задачами сборки, очистки и создания документации на весь проект.
\item *Создать два Docker-образа. Один должен компилировать Java-проект обратно в папку на компьютере пользователя, а второй забирать скомпилированные классы и исполнять их.
\item *Создать два Docker-образа. Один должен компилировать Java-проект обратно в папку на компьютере подьзователя, а второй забирать скомпилированные классы и исполнять их.
\end{itemize}
\newpage
\printnomenclature[40mm]
\end{document}

View File

@ -1,9 +1,8 @@
\documentclass[j-spec.tex]{subfiles}
\begin{document}
%\setcounter{tocdepth}{3}
\setcounter{section}{1}
\pagestyle{plain}
\sloppy
\tableofcontents
\section{Специализация: данные и функции}
\subsection{В предыдущем разделе}
@ -21,9 +20,9 @@
\begin{itemize}
\item \nom{Метод}{функция в языке программирования, принадлежащая классу};
\item \nom{Типизация}{классификация по типам};
\item \nom{Переполнение}{целочисленное переполнение (англ. integer overflow) — ситуация в компьютерной арифметике, при которой вычисленное в результате операции значение не может быть помещено в тип данных};
\item \nom{Переполнение}{целочи́сленное переполне́ние (англ. integer overflow) — ситуация в компьютерной арифметике, при которой вычисленное в результате операции значение не может быть помещено в тип данных};
\item \nom{Инициализация}{одновременной объявление переменной и присваивание ей значения};
\item \nom{Идентификатор}{идентификатор переменной -- название переменной, по которому возможно получить доступ к области памяти, соответствующей этой переменной};
\item \nom{Идентификатор}{идентификатор переменной - название переменной, по которому возможно получить доступ к области памяти, соответствующей этой переменной};
\item \nom{Typecasting}{преобразование типов переменных в типизированных языках программирования};
\item \nom{Массив}{структура данных, хранящая набор значений в непрерывной области памяти};
\end{itemize}
@ -40,26 +39,26 @@
\end{frm}
\begin{itemize}
\item Статическая -- у каждой переменной должен быть тип, и этот тип изменить нельзя. Этому свойству противопоставляется динамическая типизация.
\item Явная -- при создании переменной ей обязательно необходимо присвоить какой-то тип, явно написав это в коде. В более поздних версиях языка (с девятой) стало возможным инициализировать переменные типа \code{var}, обозначающего нужный тип тогда, когда его возможно однозначно вывести из значения справа\footnote{аналог типа \code{auto} в языке C++}. Бывают языки с неявной типизацией, например, Python.
\item Строгая(сильная) -- невозможно смешивать разнотипные данные. С другой стороны, существует, например, JavaScript, в котором запись \code{2 + true} выдаст результат \code{3}.
\item Статическая - у каждой переменной должен быть тип, и этот тип изменить нельзя. Этому свойству противопоставляется динамическая типизация;
\item Явная - при создании переменной ей обязательно необходимо присвоить какой-то тип, явно написав это в коде. В более поздних версиях языка (с 9й) стало возможным инициализировать переменные типа \code{var}, обозначающий нужный тип тогда, когда его возможно однозначно вывести из значения справа. Бывают языки с неявной типизацией, например, Python;
\item Строгая(сильная) - невозможно смешивать разнотипные данные. С другой стороны, существует JavaScript, в котором запись \code{2 + true} выдаст результат \code{3}.
\end{itemize}
\subsubsection{Антипаттерн «магические числа»}
Почти во всех примерах, которые используются для обучения, можно увидеть так называемый антипаттерн -- плохой стиль для написания кода. Числа, которые находятся справа от оператора присваивания используются в коде без пояснений. Такой антипаттерн называется «магическое число». Магическое, потому что непонятно, что это за число, почему это число именно такое и что будет, если это число изменить.
Почти во всех примерах, которые используются для обучения, можно увидеть так называемый антипаттерн - плохой стиль для написания кода. Числа, которые находятся справа от оператора присваивания используются в коде без пояснений. Такой антипаттерн называется «магическое число». Магическое, потому что непонятно, что это за число, почему это число именно такое и что будет, если это число изменить.
В реальных проектах так лучше не делать. Заранее нужно сказать, что рекомендуется помещать все числа в коде в именованные константы, которые хранятся в начале файла. Плюсом такого подхода является возможность легко корректировать значения переменных в достаточно больших проектах.
Так лучше не делать. Заранее нужно сказать, что рекомендуется помещать все числа в коде в именованные константы, которые хранятся в начале файла. Плюсом такого подхода является возможность легко корректировать значения переменных в достаточно больших проектах.
Например, в вашем коде несколько тысяч строк, а какое-то число, скажем, возраст совершеннолетия, число 18, использовалось несколько десятков раз. При использовании приложения в стране, где совершеннолетием считается 21 год вы должны будете перечитывать весь код в поисках магических «18» и исправить их на «21». В этом вопросе будет также важно не запутаться, действительно ли это 18, которые означают совершеннолетие, а не количество карманов в жилетке Анатолия Вассермана\footnote{мы то знаем, что их 26}.
Например, в вашем коде несколько тысяч строк, а какое-то число, скажем, возраст совершеннолетия, число 18, использовалось несколько десятков раз. При использовании приложения в стране, где совершеннолетием считается $21$ год вы должны будете перечитывать весь код в поисках магических «18» и исправить их на «21». В этом вопросе будет также важно не запутаться, действительно ли это $18$, которые означают совершеннолетие, а не количество карманов в жилетке Анатолия Вассермана\footnote{мы то знаем, что их 26}.
В случае с константой изменить число нужно в одном месте.
\subsection{Примитивные типы данных}
Все данные в Java делятся на две основные категории: примитивные и ссылочные. Таблица \hrf{tab:types} демонстрирует все восемь примитивных типов языка и их размерности. Чтобы отправить на хранение какие-то данные используется оператор присваивания. Присваивание в программировании -- это не тоже самое, что математическое равенство, демонстрирующее тождественность, а полноценная операция.
Все данные в Java делятся на две основные категории: примитивные и ссылочные. Таблица \hrf{tab:types} демонстрирует все восемь примитивных типов языка и их размерности. Чтобы отправить на хранение какие-то данные используется оператор присваивания. Присваивание в программировании - это не тоже самое, что математическое равенство, демонстрирующее тождественность, а полноценная операция.
Все присваивания всегда происходят справа налево, то есть сначала вычисляется правая часть, а потом результат вычислений присваивается левой. Исключений нет, именно поэтому в левой части не может быть никаких вычислений.
\begin{table}[H]
\begin{table}
\centering
\begin{tabular}{|p{17mm}|p{80mm}|p{55mm}|}
\hline
@ -86,20 +85,16 @@
\label{tab:types}
\end{table}
\begin{frm}\info
По умолчанию, создавая примитивную переменную, ей из-за примитивности данных, Java присваивает начальное значение -- ноль для числовых и ложь для булева. Что ещё раз доказывает, что мы храним там просто числа в двоичной системе счисления, мы не можем туда положить пустоту, а ноль -- это тоже значение.
\end{frm}
Шесть из восьми типов имеет диапазон значений, а значит основное их отличие в объёме занимаемой памяти. У \code{double} и \code{float} тоже есть диапазоны, но они заключаются в точности представления дробной части. Диапазоны означают, что если попытаться положить в переменную меньшего типа большее значение, произойдёт «переполнение переменной».
\subsubsection{Переполнение целочисленных переменных}
Чем именно чревато переполнение переменной, легче показать на примере (по ссылке -- \href{https://habr.com/ru/company/pvs-studio/blog/306748/}{расследование} крушения ракеты из-за переполнения переменной)
Чем именно чревато переполнение переменной легче показать на примере (по ссылке - \href{https://habr.com/ru/company/pvs-studio/blog/306748/}{расследование} крушения ракеты из-за переполнения переменной)
\begin{frm} \excl Переполнение переменных не распознаётся компилятором. \end{frm}
Если создать переменную типа \code{byte}, диапазон которого от $[-128, +127]$, и присвоить этой переменной значение $200$ произойдёт переполнение, как если попытаться влить пакет молока в напёрсток.
Если создать переменную типа byte, диапазон которого от $[-128, +127]$, и присвоить этой переменной значение $200$ произойдёт переполнение, как если попытаться влить пакет молока в напёрсток.
\begin{frm} \info Переполнение переменной -- это ситуация, в которой происходит попытка положить большее значение в переменную меньшего типа. \end{frm}
\begin{frm} \info Переполнение переменной - это ситуация, в которой происходит попытка положить большее значение в переменную меньшего типа. \end{frm}
Важным вопросом при переполнении остаётся следующий: какое в переполненной переменной останется значение? Максимальное, $127$? $200 - 127 = 73$? Какой-то мусор? Каждый язык, а зачастую и разные компиляторы одного языка ведут себя в этом вопросе по разному.
@ -114,13 +109,13 @@
\subsubsection{Задание для самопроверки}
\begin{enumerate}
\item Возможно ли объявить в Java целочисленную переменную и присвоить ей дробное значение?
\item Магическое число -- это:
\item Магическое число - это:
\begin{enumerate}
\item числовая константа без пояснений;
\item число, помогающее в вычислениях;
\item числовая константа, присваиваемая при объявлении переменной.
\end{enumerate}
\item Переполнение переменной -- это:
\item Переполнение переменной - это:
\begin{enumerate}
\item слишком длинное название переменной;
\item слишком большое значение переменной;
@ -129,11 +124,11 @@
\end{enumerate}
\subsubsection{Бинарное (битовое) представление данных}
После информации о переполнении, нельзя не сказать о том, что именно переполняется. Далее будут представлены сведения которые касаются не только языка Java но и любого другого языка программирования. Эти сведения помогут разобраться в деталях того как хранится значение переменной в программе и как, в целом, происходит работа компьютерной техники.
После разговора о переполнении, нельзя не сказать о том, что именно переполняется. Далее будут представлены сведения которые касаются не только языка Java но и любого другого языка программирования. Эти сведения помогут разобраться в деталях того как хранится значение переменной в программе и как, в целом, происходит работа компьютерной техники.
\begin{frm} \info Все современные компьютеры, так или иначе работают от электричества и являются примитивными по своей сути устройствами, которые понимают только два состояния: есть напряжение в электрической цепи или нет. Эти два состояния принято записывать в виде 1 и 0, соответственно. \end{frm}
Все данные в любой программе -- это единицы и нули. Данные в программе на Java не исключение, удобнее всего это явление рассматривать на примере примитивных данных. Поскольку в компьютере можно оперировать только двумя значениями то естественным образом используется двоичная система счисления.
Все данные в любой программе - это единицы и нули. Данные в программе на Java не исключение, удобнее всего это явление рассматривать на примере примитивных данных. Поскольку в компьютере можно оперировать только двумя значениями то естественным образом используется двоичная система счисления.
\begin{table}[H]
\centering
@ -167,21 +162,21 @@
Двоичная система счисления это система счисления с основанием два. Существуют и другие системы счисления, например, восьмеричная, но сейчас она отходит на второй план полностью уступая своё место шестнадцатеричной системе счисления. Каждая цифра в десятичной записи числа называется разрядом, аналогично в двоичной записи чисел каждая цифра тоже называется разрядом, но для компьютерной техники этот разряд называется битом.
\begin{frm}
\info Одна единица или ноль -- это один \textbf{бит} передаваемой или хранимой информации.
\info Одна единица или ноль - это один \textbf{бит} передаваемой или хранимой информации.
\end{frm}
Биты принято собирать в группы по восемь штук, по восемь разрядов, эти группы называются \textbf{байт}. В языке Java возможно оперировать минимальной единицей информации, такой как байт для этого есть соответствующий тип. Диапазон байта, согласно таблицы $[-128, +127]$, то есть байт информации может в себе содержать ровно 256 значений. Само число $127$ в двоичной записи это семиразрядное число, все разряды которого единицы (то есть байт выглядит как \code{01111111}). Последний, восьмой, самый старший бит, определяет знак числа\footnote{Для более детального понимания данной темы желательно ознакомиться с информацией о цифровой схемотехнике и хранении отрицательных чисел с применением техники дополнительного кода.}. Для нас достаточно знать формулу расчёта записи отрицательных значений:
Биты принято собирать в группы по восемь штук, по восемь разрядов, эти группы называются \textbf{байт}. В языке Java возможно оперировать минимальной единицей информации, такой как байт для этого есть соответствующий тип. Диапазон байта, согласно таблицы $[-128, +127]$, то есть байт информации может в себе содержать ровно 256 значений. Само число $127$ в двоичной записи это семиразрядное число, все разряды которого единицы (то есть байт выглядит как \code{01111111}). Последний, восьмой, самый старший бит, определяет знак числа\footnote{Здесь можно начать долгий и скучный разговор о схемотехнике и хранении отрицательных чисел с применением техники дополнительного кода.}. Достаточно знать формулу расчёта записи отрицательных значений:
\begin{enumerate}
\item в прямой записи поменять все нули на единицы и единицы на нули;
\item поставить старший бит в единицу.
\end{enumerate}
Так возможно получить на единицу меньшее отрицательное число, то есть преобразовав 0 получим -1, 1 будет -2, 2 станет -3 и так далее.
Числа б\'{о}льших разрядностей могут хранить б\'{о}льшие значения, таким образом, преобразование диапазонов из десятичной системы счисления в двоичную покажет что \code{byte} это один байт, \code{short} это два байта, то есть 16 бит, \code{int} это 4 байта то есть 32 бита, а \code{long} это 8 байт или 64 бита хранения информации.
Числа б\'{о}льших разрядностей могут хранить б\'{о}льшие значения, теперь преобразование диапазонов из десятичной системы счисления в двоичную покажет что \code{byte} это один байт, \code{short} это два байта, то есть 16 бит, \code{int} это 4 байта то есть 32 бита, а \code{long} это 8 байт или 64 бита хранения информации.
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Возможно ли число 3000000000 (три миллиарда) записать в двоичном представлении?
\item Возможно ли число 3000000000 (3 миллиарда) записать в двоичном представлении?
\item Как вы думаете, почему шестнадцатеричная система счисления вытеснила восьмеричную?
\end{enumerate}
@ -193,11 +188,11 @@
Значения в целочисленных типах могут быть только целые, никак и никогда невозможно присвоить им дробных значений. Про эти типы следует помнить следующее:
\begin{itemize}
\item \code{int} -- это самый часто используемый тип. Если сомневаетесь, какой целочисленный тип использовать, используйте \code{int};
\item все целые числа, которые пишутся в коде -- это \code{int}, даже если вы пытаетесь их присвоить переменной другого типа.
\item \code{int} - это самый часто используемый тип. Если сомневаетесь, какой целочисленный тип использовать, используйте \code{int};
\item все целые числа, которые пишутся в коде - это \code{int}, даже если вы пытаетесь их присвоить переменной другого типа.
\end{itemize}
Как \code{int} преобразуется в меньше типы? Если написать цифрами \textit{справа} число, которое может поместиться в переменную меньшего типа \textit{слева}, то статический анализатор кода его пропустит, а компилятор преобразует в меньший тип автоматически (строка 9 на рис. \hrf{pic:byte-overflow}).
Как \code{int} преобразуется в меньше типы? Если написать цифрами справа число, которое может поместиться в переменную меньшего типа слева, то статический анализатор кода его пропустит, а компилятор преобразует в меньший тип автоматически (строка 9 на рис. \hrf{pic:byte-overflow}).
\begin{figure}[H]
\centering
\includegraphics[width=12cm]{jc-02-byte-overflow.png}
@ -205,7 +200,7 @@
\label{pic:byte-overflow}
\end{figure}
Как видно, к маленькому \code{byte} успешно присваивается \code{int}. Если же написать число которое больше типа слева и, соответственно, поместиться не может, среда разработки выдает предупреждение компилятора, что ожидался \code{byte}, а передан \code{int} (строка 10 рис. \hrf{pic:byte-overflow}).
Как видно, к маленькому \code{byte} успешно присваивается \code{int}. Если же написать число которое больше типа слева и, соответственно, поместиться не может, среда разработки выдает предупреждение компилятора, что ожидался \code{byte}, а передан \code{int} (строка 10 рис \hrf{pic:byte-overflow}).
Часто нужно записать в виде числа какое-то значение большее чем может принимать \code{int}, и явно присвоить начальное значение переменной типа \code{long}.
@ -216,7 +211,7 @@
\label{pic:int-overflow}
\end{figure}
В примере на рис. \hrf{pic:int-overflow} показана попытка присвоить значение 5000000000 (пять миллиардов) переменной типа \code{long}. Из текста ошибки ясно, что невозможно положить такое большое значение в переменную типа \code{int}, а это значит, что справа \code{int}. Почему большой \code{int} без проблем присваивается к маленькому байту?
В примере на рис. \hrf{pic:int-overflow} показана попытка присвоить значение 5000000000 переменной типа \code{long}. Из текста ошибки ясно, что невозможно положить такое большое значение в переменную типа \code{int}, а это значит, что справа \code{int}. Почему большой \code{int} без проблем присваивается к маленькому байту?
\begin{figure}[H]
\centering
@ -225,16 +220,12 @@
\label{pic:overflow-solution}
\end{figure}
На рис. \hrf{pic:overflow-solution} продемонстрировано, что аналогичная ситуация возникает с типами \code{float} и \code{double}. Все дробные числа, написанные в коде -- это \code{double}, поэтому положить их во \code{float} без дополнительных усилий невозможно. В этих случаях к написанному справа числу нужно добавить явное указание на его тип.
\begin{frm}\excl
Для \code{long} пишем \code{L}, а для \code{float} -- \code{f}. Чаще всего \code{L} пишут заглавную, чтобы подчеркнуть, что тип больше, а \code{f} пишут маленькую, чтобы подчеркнуть, что мы уменьшаем тип. Но регистр в этом конкретном случае значения не имеет, можно писать и так и так.
\end{frm}
На рис. \hrf{pic:overflow-solution} продемонстрировано, что аналогичная ситуация возникает с типами \code{float} и \code{double}. Все дробные числа, написанные в коде - это \code{double}, поэтому положить их во \code{float} без дополнительных усилий невозможно. В этих случаях к написанному справа числу нужно добавить явное указание на его тип. Для \code{long} пишем \code{L}, а для \code{float} - \code{f}. Чаще всего \code{L} пишут заглавную, чтобы подчеркнуть, что тип больше, а \code{f} пишут маленькую, чтобы подчеркнуть, что мы уменьшаем тип. Но регистр в этом конкретном случае значения не имеет, можно писать и так и так.
\subsubsection{Числа с плавающей запятой (точкой)}
Как видно из таблицы \hrf{tab:types}, два из восьми типов не имеют диапазонов значений. Это связано с тем, что диапазоны значений \code{float} и \code{double} заключаются не в величине возможных хранимых чисел, а в точности этих чисел после запятой.
Как видно из таблицы \hrf{tab:types}, два из восьми типов не имеют диапазонов значений. Это связано с тем, что диапазоны значений флоута и дабла заключаются не в величине возможных хранимых чисел, а в точности этих чисел после запятой.
\begin{frm} \info Числа с плавающей запятой в англоязычной литературе называются числа с плавающей точкой (от англ. floating point). Такое различие связано с тем, что в русскоязычной литературе принято отделять дробную часть числа запятой, а в европейской и американской -- точкой. \end{frm}
\begin{frm} \info Числа с плавающей запятой в англоязычной литературе называются числа с плавающей точкой (от англ. floating point). Такое различие связано с тем, что в русскоязычной литературе принято отделять дробную часть числа запятой, а в европейской и американской - точкой. \end{frm}
Хранение чисел с плавающей запятой\footnote{хорошо и подробно, но на С, в посте на \href{https://habr.com/ru/post/112953/}{Хабре}.} работает по стандарту IEEE 754 (1985 г). Для работы с числами с плавающей запятой на аппаратурном уровне к обычному процессору добавляют математический сопроцессор (FPU, floating point unit).
@ -242,16 +233,14 @@
\centering
\begin{subfigure}[b]{0.48\textwidth}
\centering
\def\svgwidth{\textwidth}
\includesvg{pics/jc-02-float-struct.svg}
\includesvg[width=\textwidth]{pics/jc-02-float-struct.svg}
\caption{double}
\label{pic:float-double}
\end{subfigure}
\hfill
\begin{subfigure}[b]{0.48\textwidth}
\centering
\def\svgwidth{\textwidth}
\includesvg{pics/jc-02-float-struct32.svg}
\includesvg[width=\textwidth]{pics/jc-02-float-struct32.svg}
\caption{float}
\label{pic:float-float}
\end{subfigure}
@ -259,7 +248,7 @@
\label{pic:float-struct}
\end{figure}
Рисунок \hrf{pic:float-struct} демонстрирует, как распределяются биты в числах с плавающей запятой разных разрядностей, где S -- Sign (знак), E -- Exponent, 8 (или 11) разрядов поля порядка, экспонента, M -- Mantissa, 23 (или 52) бита мантиссы, дробная часть числа. Также на рисунке показана так называемая, мнимая единица, она всегда есть в самом старшем разряде мантиссы, поэтому её всегда подразумевают, но в явном виде не хранят, экономя один бит информации.
Рисунок \hrf{pic:float-struct} демонстрирует, как распределяются биты в числах с плавающей запятой разных разрядностей, где S - Sign (знак), E - Exponent (8(11) разрядов поля порядка, экспонента), M - Mantissa (23(52) бита мантиссы, дробная часть числа).
Если попытаться уложить весь стандарт в два предложения, то получится примерно следующее: получить число в соответствующих разрядностях возможно по формулам:
\begin{equation*}
@ -283,7 +272,7 @@
Отсюда становится очевидно, что чем сложнее мантисса и чем меньше порядок, тем более точные и интересные числа мы можем получить.
\end{frm}
Возьмём для примера число $-0,15625$, чтобы понять как его записывать, откинем знак, это будет единица в разряде, отвечающем за знак, и посчитаем мантиссу с порядком. Представим число как положительное и будем от него последовательно отнимать числа, являющиеся отрицательными степенями двойки, чтобы получить максимально близкое к нулю значение, но не превысить его.
Возьмём для примера число $-0,15625$, чтобы понять как его записывать, откинем знак, это будет единица в разряде, отвечающем за знак, и посчитаем мантиссу с порядком. Представим число как положительное и будем от него последовательно отнимать числа, являющиеся отрицательными степенями двойки, чтобы получить максимально близкое к нулю значение.
\begin{equation*}
\begin{gathered}
@ -293,16 +282,17 @@
Очевидно, что $-1$ и $-2$ степени отнять не получится, поскольку мы явно уходим за границу нуля, а вот $-3$ прекрасно отнимается, значит порядок будет $127-3 = 124$, осталось понять, что получится в мантиссе.
Видим, что оставшееся после первого вычитания ($0,15625 - 0,125$) число -- это $2^{-5}$. Значит в мантиссе пишем \code{01} и остальные нули, то есть слева направо указываем, какие степени после $-3$ будут нужны. $-4$ не нужна, а $-5$ нужна.
Видим, что оставшееся после первого вычитания ($0,15625 - 0,125$) число - это $2^{-5}$. Значит в мантиссе пишем \code{01} и остальные нули, то есть слева направо указываем, какие степени после $-3$ будут нужны. $-4$ не нужна, а $-5$ нужна.
Получится, что
\begin{equation*}
\begin{gathered}
(-1)^1 \times 2^{(124-127)} \times (1 + \frac{2097152}{2^{23}}) = -0,15625 \\
(-1)^1 \times 2^{(124-127)} \times (1 + \frac{2097152}{2^{23}}) = 1,15652 \\
\text{или, тождественно,}\\
(-1)^1 \times 1,01e-3 = (-1)^1 \times 1 \times2^{-3} + 0\times2^{-4} + 1\times2^{-5} = \\
(-1)^1 \times 1 \times0,125 + 0\times0,0625 + 1\times0,03125 = 0,125 + 0,03125 = \\
(-1)^1 \times 0,15625 = -0,15625
(-1)^1 \times 1,01e-3 = \\
1\times2^{-3} + 0\times2^{-4} + 1\times2^{-5} = \\
1\times0,125 + 0\times0,0625 + 1\times0,03125 = \\
0,125 + 0,03125 = 0,15625
\end{gathered}
\end{equation*}
@ -329,7 +319,7 @@
\item Почему нельзя напрямую сравнивать целочисленные данные и числа с плавающей запятой, даже если там точно лежит число без дробной части?
\item Внутри переполненной переменной остаётся значение:
\begin{enumerate}
\item переданное -- максимальное для типа;
\item переданное - максимальное для типа;
\item максимальное для типа;
\item не определено.
\end{enumerate}
@ -384,30 +374,24 @@
\label{table:utf-8-ascii}
\end{table}
Тип \code{char} единственный беззнаковый целочисленный тип в языке, то есть его старший разряд хранит полезное значение, а не признак положительности. Тип целочисленный но по умолчанию среда исполнения интерпретирует его как символ по таблице utf-8 (см. фрагмент в таблице \hrf{table:utf-8-ascii}).
\begin{frm}\excl
В языке Java есть разница между одинарными и двойными кавычками.
\end{frm}
В одинарных кавычках всегда записывается символ (\code{char}), который на самом деле является целочисленным значением, а в двойных кавычках всегда записывается строка, которая фактически является экземпляром класса \code{String}. Поскольку типизация строгая, то невозможно записать в \code{char} строки, а в строки числа.
Тип \code{char} единственный беззнаковый целочисленный тип в языке, то есть его старший разряд хранит полезное значение, а не признак положительности. Тип целочисленный но по умолчанию среда исполнения интерпретирует его как символ по таблице utf-8 (см фрагмент в таблице \hrf{table:utf-8-ascii}). В языке Java есть разница между одинарными и двойными кавычками. В одинарных кавычках всегда записывается символ, который на самом деле является целочисленным значением, а в двойных кавычках всегда записывается строка, которая фактически является экземпляром класса \code{String}. Поскольку типизация строгая, то невозможно записать в \code{char} строки, а в строки числа.
\begin{frm} \info В Java есть три основных понятия, связанных с данными переменными и использованием значений: объявление, присваивание, инициализация.
Для того чтобы \textit{объявить} переменную, нужно написать её тип и название, также часто вместо названия можно встретить термин идентификатор.
Далее в любой момент можно \textit{присвоить} этой переменной значение, то есть необходимо написать идентификатор, использовать оператор присваивания, и справа написать значение, которое вы хотите присвоить данной переменной. Поставить в конце строки точку с запятой.
Далее в любой момент можно \textit{присвоить} этой переменной значение, то есть необходимо написать идентификатор использовать оператор присваивания и справа написать значение, которое вы хотите присвоить данной переменной, поставить в конце строки точку с запятой.
Также существует понятие \textit{инициализации} -- это когда объединяются на одной строке объявление и присваивание.\end{frm}
Также существует понятие \textit{инициализации} - это когда объединяются на одной строке объявление и присваивание.\end{frm}
\subsubsection{Преобразование типов}
Java -- это язык со строгой статической типизацией, но преобразование типов в ней всё равно есть. Простыми словами, преобразование типов -- это когда компилятор видит, что типы переменных по разные стороны присваивания разные, начинает разрешать это противоречие, успешно или нет. Преобразование типов бывает явное и неявное. Неявное преобразование типов происходит когда компилятор в состоянии сам преобразовать типы, явное, когда ему нужна помощь.
Java - это язык со строгой статической типизацией, но преобразование типов в ней всё равно есть. Простыми словами, преобразование типов - это когда компилятор видит, что типы переменных по разные стороны присваивания разные, начинает разрешать это противоречие. Преобразование типов бывает явное и неявное.
\begin{frm}
\info В разговоре или в сообществах можно услышать или прочитать термины тайпкастинг, кастинг, каст, кастануть, и другие производные от английского typecasting.
\end{frm}
Неявное преобразование типов происходит, когда присваиваются числа переменным меньшей размерности, чем \code{int}. Число справа это \code{int}, а значит 32 разряда, а слева, например, \code{byte}, и в нём всего 8 разрядов, но ни среда ни компилятор не «поругались», потому что значение в большом \code{int} не превысило 8 разрядов маленького \code{byte}. Итак неявное преобразование типов происходит в случаях, когда, «всё и так понятно». В случае, если неявное преобразование невозможно, статический анализатор кода выдаёт ошибку, что ожидался один тип, а был дан другой.
Неявное преобразование типов происходит, когда присваиваются числа переменным меньшей размерности, чем \code{int}. Число справа это \code{int}, а значит 32 разряда, а слева, например, \code{byte}, и в нём всего 8 разрядов, но ни среда ни компилятор не поругались, потому что значение в большом \code{int} не превысило 8 разрядов маленького \code{byte}. Итак неявное преобразование типов происходит в случаях, когда, «всё и так понятно». В случае, если неявное преобразование невозможно, статический анализатор кода выдаёт ошибку, что ожидался один тип, а был дан другой.
Явное преобразование типов происходит, когда мы явно пишем в коде, что некоторое значение должно иметь определённый тип. Этот вариант приведения типов тоже был рассмотрен, когда к числам дописывались типовые квалификаторы \code{L} и \code{f}. Но чаще всего случается, что происходит присваивание переменным не тех значений, которые были написаны в тексте программы, а те, которые получились в результате каких-то вычислений.
\begin{figure}[H]
@ -422,33 +406,33 @@ Java -- это язык со строгой статической типиза
\centering
\includegraphics[width=12cm]{jc-02-byte-cast-fix.png}
\caption{Верное приведение типов}
\label{pic:byte-cast-error}
\label{pic:byte-cast-fix}
\end{figure}
\subsubsection{Константность}
Constare -- (лат. стоять твёрдо). Константность это свойство неизменяемости. В Java ключевое слово \code{const} не реализовано, хоть и входит в список ключевых, зарезервированных. Константы создаются при помощи ключевого слова \code{final}. Ключевое слово \code{final} возможно применять не только с примитивами, но и со ссылочными типами, методами, классами.
Constare - (лат. стоять твёрдо). Константность это свойство неизменяемости. В Java ключевое слово \code{const} не реализовано, хоть и входит в список ключевых, зарезервированных. Константы создаются при помощи ключевого слова \code{final}. Ключевое слово файнал возможно применять не только с примитивами, но и со ссылочными типами, методами, классами.
\begin{frm}
\info Константа -- это переменная или идентификатор с конечным значением.
\info Константа - это переменная или идентификатор с конечным значением.
\end{frm}
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Какая таблица перекодировки используется для представления символов?
\item Каких действий требует от программиста явное преобразование типов?
\item какое значение будет содержаться в переменной a после выполнения строки \code{int а = 10.0f/3.0f;}
\item какое значение будет содержаться в переменной a после выполнения строки int а = 10.0f/3.0f;
\end{enumerate}
\subsection{Ссылочные типы данных, массивы}
Ссылочные типы данных -- это все типы данных, кроме восьми перечисленных примитивных. Самым простым из ссылочных типов является массив. Фактически, массив выведен на уровень языка и не имеет специального ключевого слова.
Ссылочные типы данных - это все типы данных, кроме восьми перечисленных примитивных. Самым простым из ссылочных типов является массив. Фактически массив выведен на уровень языка и не имеет специального ключевого слова.
Ссылочные типы отличаются от примитивных местом хранения информации. В \textit{примитивах} данные хранятся там, где существует переменная и где написан её идентификатор, а по идентификатору \textit{ссылочного} типа хранится не значение, а ссылка. Ссылку можно представить как ярлык на рабочем столе, то есть, очевидно, что непосредственная информация хранится не там, где написан идентификатор. Такое явное разделение идентификатора переменной и данных важно помнить и понимать при работе с ООП.
Ссылочные типы отличаются от примитивных местом хранения информации. В примитивах данные хранятся там, где существует переменная и где написан её идентификатор, а по идентификатору ссылочного типа хранится не значение, а ссылка. Ссылку можно представить как ярлык на рабочем столе, то есть очевидно, что непосредственная информация хранится не там, где написан идентификатор. Такое явное разделение идентификатора переменной и данных важно помнить и понимать при работе с ООП.
\begin{frm} \info \textbf{Массив} -- это единая, сплошная область данных, в связи с чем в массивах возможно осуществление доступа по индексу \end{frm}
\begin{frm} \info \textbf{Массив} - это единая, сплошная область данных, в связи с чем в массивах возможно осуществление доступа по индексу \end{frm}
Самый младший индекс любого массива -- \textit{ноль}, поскольку \textbf{индекс} -- это значение смещения по элементам относительно начального адреса массива. То есть, для получения самого первого элемента нужно сместиться на ноль шагов. Очевидно, что самый последний элемент в массиве из десяти значений, будет храниться по \textit{девятому} индексу.
Самый младший индекс любого массива - ноль, поскольку \textbf{индекс} - это значение смещения по элементам относительно начального адреса массива. То есть, для получения самого первого элемента нужно сместиться на ноль шагов. Очевидно, что самый последний элемент в массиве из десяти значений, будет храниться по девятому индексу.
Массивы возможно создавать несколькими способами (листинг \hrf{lst:array-init}). В общем виде объявление -- это тип, квадратные скобки как обозначение того, что это будет массив из переменных этого типа, идентификатор (строка \hrf{codeline:arr-define}). Инициализировать массив можно либо ссылкой на другой массив (строка \hrf{codeline:arr-link}), пустым массивом (строка \hrf{codeline:arr-new}) или заранее заданными значениями, записанными через запятую в фигурных скобках (строка \hrf{codeline:arr-values}). Присвоить в процессе работы идентификатору возможно только значение ссылки из другого идентификатора или новый пустой массив.
Массивы возможно создавать несколькими способами (листинг \hrf{lst:array-init}). В общем виде объявление - это тип, квадратные скобки как обозначение того, что это будет массив из переменных этого типа, идентификатор (строка \hrf{codeline:arr-define}). Инициализировать массив можно либо ссылкой на другой массив (строка \hrf{codeline:arr-link}), пустым массивом (строка \hrf{codeline:arr-new}) или заранее заданными значениями, записанными через запятую в фигурных скобках (строка \hrf{codeline:arr-values}). Присвоить в процессе работы идентификатору возможно только значение ссылки из другого идентификатора или новый пустой массив.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Объявление массива},label={lst:array-init}]
int[] array0;<@ \label{codeline:arr-define} @>
@ -456,18 +440,16 @@ Constare -- (лат. стоять твёрдо). Константность эт
int[] array2 = new int[5];<@ \label{codeline:arr-new} @>
int[] array3 = {5, 4, 3, 2, 1};<@ \label{codeline:arr-values} @>
array2 = {1, 2, 3, 4, 5}; // <@\lh{dkgreen}{<-- здесь недопустимо присваивание}@> <@ \label{codeline:arr-invalid} @>
array2 = {1, 2, 3, 4, 5}; // <@%\lh{dkgreen}{<-- здесь недопустима инициализация}@> <@ \label{codeline:arr-invalid} @>
\end{lstlisting}
Если мы не определяем переменную, понятно, данные мы хранить не планируем. Если определяем примитивную, помним, она инициализируется нулём, а если мы определяем ссылочный идентификатор, он имеет начальное значение \code{null}, то есть явно демонстрирует, что не ссылается ни на какой объект. \textbf{Нулевой указатель} -- это гораздо более серьёзное явление, чем просто временное отсутствие объекта по идентификатору, очень часто это не инициализированные объекты и попытки вызова невозможных методов. Поэтому в работе очень часто помогает понять, что именно пошло не так \code{NullPointerException}.
\begin{frm} \excl Никак и никогда нельзя присвоить идентификатору целый готовый массив в процессе работы, нельзя стандартными средствами переприсвоить ряд значений части массива (так называемые слайсы или срезы). \end{frm}
\begin{frm} \excl Никак и никогда нельзя присвоить идентификатору целый готовый массив (создаваемый здесь и сейчас) в процессе работы, нельзя стандартными средствами переприсвоить ряд значений части массива (так называемые слайсы или срезы). \end{frm}
Массивы бывают как одномерные, так и многомерные. Многомерный массив -- это всегда массив из массивов меньшего размера: двумерный массив -- это массив одномерных, трёхмерный -- массив двумерных и так далее. Правила инициализации у них не отличаются. Преобразовать тип массива нельзя никогда, но можно преобразовать тип каждого отдельного элемента при чтении. Это связано с тем, что под массивы сразу выделяется непрерывная область памяти, а со сменой типа всех значений массива эту область нужно будет или значительно расширять или значительно сужать.
Массивы бывают как одномерные, так и многомерные. Многомерный массив - это всегда массив из массивов меньшего размера: двумерный массив - это массив одномерных, трёхмерный - массив двумерных и так далее. Правила инициализации у них не отличаются. Преобразовать тип массива нельзя никогда, но можно преобразовать тип каждого отдельного элемента при чтении. Это связано с тем, что под массивы сразу выделяется непрерывная область памяти, а со сменой типа всех значений массива эту область нужно будет или значительно расширять или значительно сужать.
Ключевое слово \code{final} работает только с идентификатором массива, то есть не запрещает изменять значения его элементов.
Если алгоритм приложения предполагает создание нижних измерений массива в процессе работы программы, то при инициализации массива верхнего уровня не следует указывать размерности нижних уровней. Это связано с тем, что при инициализации, Java сразу выделяет память под все измерения, а присваивание нижним измерениям новых ссылок на создаваемые в процессе работы массивы, будет пересоздавать области памяти, получается небольшая утечка памяти.
Если логика программы предполагает создание нижних измерений массива в процессе работы программы, то при инициализации массива верхнего уровня не следует указывать размерности нижних уровней. Это связано с тем, что при инициализации, Java сразу выделяет память под все измерения, а присваивание нижним измерениям новых ссылок на создаваемые в процессе работы массивы, будет пересоздавать области памяти, получается небольшая утечка памяти.
Прочитать из массива значение возможно обратившись к ячейке массива по индексу. Записать в массив значение возможно обратившись к ячейке массива по индексу, и применив оператор присваивания.
\begin{lstlisting}[language=Java,style=JCodeStyle]
@ -493,12 +475,12 @@ Constare -- (лат. стоять твёрдо). Константность эт
\subsection{Базовый функционал языка}
\subsubsection{Математические операторы}
Математические операторы работают как и предполагается -- складывают, вычитают, делят, умножают, делают это по приоритетам, известным нам с пятого класса, а если приоритет одинаков -- слева направо. Специального оператора возведения в степень как в Python нет. Единственное, что следует помнить, что оператор присваивания продолжает быть оператором присваивания, а не является математическим тождеством, а значит сначала посчитается всё, что слева, а потом результат попробует присвоиться переменной справа. Припоминаем какие есть особенности у операции целочисленного деления, связанные с отбрасыванием дробной части.
Математические операторы работают как и предполагается - складывают, вычитают, делят, умножают, делают это по приоритетам известным нам с пятого класса, а если приоритет одинаков - слева направо. Специального оператора возведения в степень как в пайтоне нет. Единственное, что следует помнить, что оператор присваивания продолжает быть оператором присваивания, а не является математическим равенством, а значит сначала посчитается всё, что слева, а потом результат попробует присвоиться переменной справа. Припоминаем что там за дела с целочисленным делением и отбрасыванием дробной части.
\subsubsection{Условия}
Условия представлены в языке привычными \code{if}, \code{else if}, \code{else}, «если», «иначе если», «в противном случае», которые являются единым оператором выбора, то есть, если исполнение программы пошло по одной из веток, то в другую ветку условия программа никогда не зайдёт. Каждая ветвь условного оператора -- это отдельный кодовый блок со своим окружением и локальными переменными.
Условия представлены в языке привычными \code{if}, \code{else if}, \code{else}, «если», «иначе если», «в противном случае», которые являются единым оператором выбора, то есть если исполнение программы пошло по одной из веток, то в другую ветку условия программа точно не зайдёт. Каждая ветвь условного оператора - это отдельный кодовый блок со своим окружением и локальными переменными.
Существует альтернатива оператору \code{else if} -- использование оператора \code{switch}, который позволяет осуществлять множественный выбор между числовыми значениями. У оператора есть ряд особенностей:
Существует альтернатива оператору \code{else if} - использование оператора \code{switch}, который позволяет осуществлять множественный выбор между числовыми значениями. У оператора есть ряд особенностей:
\begin{itemize}
\item это оператор, состоящий из одного кодового блока, то есть сегменты кода находятся в одной области видимости. Если не использовать оператор \code{break}, есть риск «проваливаться» в следующие кейсы;
\item нельзя создать диапазон значений;
@ -513,12 +495,12 @@ Constare -- (лат. стоять твёрдо). Константность эт
\item \code{for (;;) {}}
\end{itemize}
Цикл -- это набор повторяющихся до наступления условия действий. \code{while} -- самый простой, чаще всего используется, когда нужно описать бесконечный цикл. \code{do-while} единственный цикл с постусловием, то есть сначала выполняется тело, а затем принимается решение о необходимости зацикливания, используется для ожидания ответов на запрос и возможного повторения запроса по условию. \code{for} -- классический счётный цикл, его почему-то программисты любят больше всего.
Цикл - это набор повторяющихся до наступления условия действий. \code{while} - самый простой, чаще всего используется, когда нужно описать бесконечный цикл. \code{do-while} единственный цикл с постусловием, то есть сначала выполняется тело, а затем принимается решение о необходимости зацикливания, используется для ожидания ответов на запрос и возможного повторения запроса по условию. \code{for} - классический счётный цикл, его почему-то программисты любят больше всего.
Существует также активно пропагандируемый цикл -- \code{foreach}, работает не совсем очевидным образом, для понимания его работы необходимо ознакомиться с ООП и понятием итератора.
Существует также активно пропагандируемый цикл - \code{foreach}, работает не совсем очевидным образом, для понимания его работы необходимо ознакомиться с ООП и понятием итератора.
\subsubsection{Бинарные арифметические операторы}
В современных реалиях мегамощных компьютеров вряд ли кто-то задумывается об оптимизации скорости выполнения программы или экономии занимаемой памяти. Но всё меняется, когда программист впервые принимает сложное решение: запрограммировать микроконтроллер или другой «интернет вещей». Там в вашем распоряжении пара сотен килобайт памяти, если очень повезёт, в которые нужно не только как-то вложить текст программы и исполняемый бинарный код, но и какие-то промежуточные, пользовательские и другие данные, буферы обмена и обработки. Другая ситуация, в которой нужно начинать «думать о занимаемом пространстве» это разработка протоколов передачи данных, чтобы протокол был быстрый, не передавал по сети большие объёмы данных и быстро преобразовывался. На помощь приходит натуральная для информатики система счисления, двоичная.
В современных реалиях мегамощных компьютеров вряд ли кто-то задумывается об оптимизации скорости выполнения программы или экономии занимаемой памяти. Но всё меняется, когда программист впервые принимает сложное решение: запрограммировать микроконтроллер или другой «интернет вещей». Там в вашем распоряжении жалкие пара сотен килобайт памяти, если очень повезёт, в которые нужно не только как-то вложить текст программы и исполняемый бинарный код, но и какие-то промежуточные, пользовательские и другие данные, буферы обмена и обработки. Другая ситуация, в которой нужно начинать «думать о занимаемом пространстве» это разработка протоколов передачи данных, чтобы протокол был быстрый, не передавал по сети большие объёмы данных и быстро преобразовывался. На помощь приходит натуральная для информатики система счисления, двоичная.
Манипуляции двоичными данными представлены в Джава следующими операторами:
\begin{itemize}
@ -532,7 +514,7 @@ Constare -- (лат. стоять твёрдо). Константность эт
Литеральные «и», «или», «не» уже знакомы по условным операторам. Литеральные операции применяются ко всему числовому литералу целиком, а не к каждому отдельному биту. Их особенность заключается в том, как язык программирования интерпретирует числа.
\begin{frm} \info В Java в литеральных операциях может участвовать только тип \code{boolean}, в то время, как, например, C++ воспринимает любой ненулевой целочисленный литерал как истину, а нулевой, соответственно, как ложь.
\begin{frm} \info В Java в литеральных операциях может участвовать только тип \code{boolean}, а C++ воспринимает любой ненулевой целочисленный литерал как истину, а нулевой, соответственно, как ложь.
\end{frm}
Логика формирования значения при этом остаётся такой же, как и при битовых операциях.
@ -584,7 +566,8 @@ Constare -- (лат. стоять твёрдо). Константность эт
\label{table:bin-truth-tables}
\end{table}
Когда говорят о битовых операциях, так или иначе, появляется необходимость поговорить о таблицах истинности. В таблице \hrf{table:bin-truth-tables} вы видите таблицы истинности для арифметических битовых операций. Битовые операции отличаются тем, что для неподготовленного взгляда они производят почти магические действия, потому что манипулируют двоичным представлением числа.
Когда говорят о битовых операциях волей-неволей появляется необходимость поговорить о таблицах истинности. В таблице \hrf{table:bin-truth-tables} вы видите таблицы истинности для арифметических битовых операций. Битовые операции отличаются тем, что для неподготовленного взгляда они производят почти магические действия, потому что манипулируют двоичным представлением числа.
\begin{figure}[H]
\begin{arithmetic}
@ -619,45 +602,45 @@ Constare -- (лат. стоять твёрдо). Константность эт
\hline
Число & Бинарное & Сдвиг \\ [0.5ex]
\hline\hline
2 & 00000010 & \code{2 << 0} \\
4 & 00000100 & \code{2 << 1} \\
8 & 00001000 & \code{2 << 2} \\
16 & 00010000 & \code{2 << 3} \\
32 & 00100000 & \code{2 << 4} \\
64 & 01000000 & \code{2 << 5} \\
128 & 10000000 & \code{2 << 6} \\
2 & 000000010 & \code{2 << 0} \\
4 & 000000100 & \code{2 << 1} \\
8 & 000001000 & \code{2 << 2} \\
16 & 000010000 & \code{2 << 3} \\
32 & 000100000 & \code{2 << 4} \\
64 & 001000000 & \code{2 << 5} \\
128 & 010000000 & \code{2 << 6} \\
\hline
\end{tabular}
\begin{tabular}{||c|c|c||}
\hline
Число & Бинарное & Сдвиг \\ [0.5ex]
\hline\hline
128 & 10000000 & \code{128 >> 0} \\
64 & 01000000 & \code{128 >> 1} \\
32 & 00100000 & \code{128 >> 2} \\
16 & 00010000 & \code{128 >> 3} \\
8 & 00001000 & \code{128 >> 4} \\
4 & 00000100 & \code{128 >> 5} \\
2 & 00000010 & \code{128 >> 6} \\
128 & 010000000 & \code{128 >> 0} \\
64 & 001000000 & \code{128 >> 1} \\
32 & 000100000 & \code{128 >> 2} \\
16 & 000010000 & \code{128 >> 3} \\
8 & 000001000 & \code{128 >> 4} \\
4 & 000000100 & \code{128 >> 5} \\
2 & 000000010 & \code{128 >> 6} \\
\hline
\end{tabular}
\caption{Битовые сдвиги}
\label{table:bit-shift}
\end{table}
С битовыми сдвигами работать гораздо интереснее и выгоднее. Они производят арифметический сдвиг значения слева на количество разрядов, указанное справа, в таблице \hrf{table:bit-shift} представлены восьмиразрядные беззнаковые числа, в битовом представлении это одна единственная единица, находящаяся в разных разрядах числа. Это демонстрация сдвига на один разряд влево, и, как следствие, умножение на два. Обратная ситуация со сдвигом вправо, он является целочисленным делением.
С битовыми сдвигами работать гораздо интереснее и выгоднее. Они производят арифметический сдвиг значения слева на количество разрядов, указанное справа, в таблице \hrf{table:bit-shift} представлены числа, в битовом представлении это одна единственная единица, находящаяся в разных разрядах числа. Это демонстрация сдвига на один разряд влево, и, как следствие, умножение на два. Обратная ситуация со сдвигом вправо, он является целочисленным делением.
\begin{frm} \info
\begin{itemize}
\item \code{X && Y} -- литеральная;
\item \code{X || Y} -- литеральная;
\item \code{!X} -- литеральная;
\item \code{N << K} -- $N * 2^K$;
\item \code{N >> K} -- $N / 2^K$;
\item \code{x & y} -- битовая. 1 если оба x = 1 и y = 1;
\item \code{x | y} -- битовая. 1 если хотя бы один из x = 1 или y = 1;
\item \code{~x} -- битовая. 1 если x = 0;
\item \code{x ^ y} -- битовая. 1 если x отличается от y.
\item \code{X && Y} - литеральная;
\item \code{X || Y} - литеральная;
\item \code{!X} - литеральная;
\item \code{N << K} - $N * 2^K$;
\item \code{N >> K} - $N / 2^K$;
\item \code{x & y} - битовая. 1 если оба x = 1 и y = 1;
\item \code{x | y} - битовая. 1 если хотя бы один из x = 1 или y = 1;
\item \code{~x} - битовая. 1 если x = 0;
\item \code{x ^ y} - битовая. 1 если x отличается от y.
\end{itemize}
\end{frm}
@ -669,10 +652,10 @@ Constare -- (лат. стоять твёрдо). Константность эт
\end{enumerate}
\subsection{Функции}
\textbf{Функция} -- это исполняемый блок кода. Функция, принадлежащая классу называется \textbf{методом}.
\textbf{Функция} - это исполняемый блок кода. Функция, принадлежащая классу называется \textbf{методом}.
\begin{lstlisting}[language=Java,style=JCodeStyle]
void method(int param1, int param2) {
void int method(int param1, int param2) {
//function body
}
@ -681,9 +664,9 @@ Constare -- (лат. стоять твёрдо). Константность эт
}
\end{lstlisting}
При объявлении функции в круглых скобках указываются параметры, а при вызове -- аргументы.
При объявлении функции в круглых скобках указываются параметры, а при вызове - аргументы.
У функций есть правила именования: функция -- это переходный глагол совершенного вида в настоящем времени (вернуть, посчитать, установить, создать), часто снабжаемый дополнением, субъектом действия. Методы в Java пишутся lowerCamelCase. Важно, в каком порядке записаны параметры метода, от этого будет зависеть порядок передачи в неё аргументов. Методы обособлены и их параметры локальны, то есть не видны другим функциям.
У функций есть правила именования: функция - это переходный глагол совершенного вида в настоящем времени (вернуть, посчитать, установить, создать), часто снабжаемый дополнением, субъектом действия. Методы в Java пишутся lowerCamelCase. Важно, в каком порядке записаны параметры метода, от этого будет зависеть порядок передачи в неё аргументов. Методы обособлены и их параметры локальны, то есть не видны другим функциям.
\begin{frm}
\excl Нельзя писать функции внутри других функций.
\end{frm}
@ -692,22 +675,23 @@ Constare -- (лат. стоять твёрдо). Константность эт
Возвращаемые из методов значения появляются в том месте, где метод был вызван. Если будет вызвано несколько методов, то весь контекст исполнения первого метода сохраняется, кладётся (на стек) в стопку уже вызванных методов и процессор идёт выполнять только что вызванный второй метод. По завершении вызванного второго метода, мы снимаем со стека лежащий там контекст первого метода, кладём в него вернувшееся из второго метода значение, если оно есть, и продолжаем исполнять первый метод.
Возвращаемого значения у метода может и не быть, в некоторых языках такие функции и методы называются процедурами, а в Java для них просто придумали специальное возвращаемое значение -- \code{void}. Void (от англ. пустота), интересно отметить, что это не какое-то простое emptyness, а серьёзное масштабное космическое void, чтобы подчеркнуть, что метод совсем ничего точно не возвращает.
\textbf{Вызов метода} - это, по смыслу, тоже самое, что подставить в код сразу его возвращаемое значение.
\textbf{Вызов метода} -- это, по смыслу, тоже самое, что подставить в код сразу его возвращаемое значение.
\textbf{Сигнатура метода} - это имя метода и его параметры. В сигнатуру метода не входит возвращаемое значение. Нельзя написать два метода с одинаковой сигнатурой.
\textbf{Сигнатура метода} -- это имя метода и его параметры. В сигнатуру метода не входит возвращаемое значение. Нельзя написать два метода с одинаковой сигнатурой.
\textbf{Перегрузка методов} - это механизм языка, позволяющий написать методы с одинаковыми названиями и разными оставшимися частями сигнатуры, чтобы получить единообразие при вызове семантически схожих методов с разнотипными данными.
\textbf{Перегрузка методов} -- это механизм языка, позволяющий написать методы с одинаковыми названиями и разными оставшимися частями сигнатуры, чтобы получить единообразие при вызове семантически схожих методов с разнотипными данными.
\subsection*{Практическое задание}
\subsection{Практическое задание}
\begin{enumerate}
\item Написать метод «Шифр Цезаря», с булевым параметром зашифрования и расшифрования и числовым ключом;
\item Написать метод, принимающий на вход массив чисел и параметр n. Метод должен осуществить циклический (последний элемент при сдвиге становится первым) сдвиг всех элементов массива на n позиций;
\item Написать метод, которому можно передать в качестве аргумента массив, состоящий строго из единиц и нулей (целые числа типа \code{int}). Метод должен заменить единицы в массиве на нули, а нули на единицы и не содержать ветвлений. Написать как можно больше вариантов метода.
\end{enumerate}
\newpage
% \subsection*{Задания к семинару}
% \begin{itemize}
% \item Сравнить без условий две даты, представленные в виде трёх чисел гггг-мм-дд;
% \end{itemize}
\printnomenclature[40mm]
\end{document}

View File

@ -15,14 +15,14 @@
\begin{itemize}
\item \nom{Класс}{определяет форму и сущность объекта и является логической конструкцией, на основе которой построен весь язык Java. Определяет новый тип данных};
\item \nom{Объект}{конкретный экземпляр класса, созданный в программе};
\item \nom{Статика}{(статический контекст) static -- (от греч. неподвижный) -- раздел механики, в котором изучаются условия равновесия механических систем под действием приложенных к ним сил и возникших моментов. В языке программирования Java -- принадлежность поля и его значения не объекту, а классу, и, как следствие, доступность такого поля и его значения в единственном экземпляре всем объектам класса.};
\item \nom{Статика}{(статический контекст) static - (от греч. неподвижный) — раздел механики, в котором изучаются условия равновесия механических систем под действием приложенных к ним сил и возникших моментов. В языке программирования Java - принадлежность поля и его значения не объекту, а классу, и, как следствие, доступность такого поля и его значения в единственном экземпляре всем объектам класса.};
\item \nom{Стек}{структура данных, работающая по принципу LIFO (last in, first out) или FILO (first in, last out). Стековая память отвечает за хранение ссылок на объекты кучи и за хранение типов значений (также известных в Java как примитивные типы), которые содержат само значение, а не ссылку на объект из кучи.};
\item \nom{Куча}{адресуемое пространство оперативной памяти компьютера. Куча содержит все объекты, созданные в вашем приложении, независимо от того, какой поток создал объект.};
\item \nom{Сборщик мусора}{специализированная подпрограмма, очищающая память от неиспользуемых объектов.};
\item \nom{Конструктор}{это частный случай метода, предназначенный для инициализации объектов при создании в Java.};
\item \nom{Инкапсуляция}{(англ. encapsulation, от лат. in capsula) — в информатике, процесс разделения элементов абстракций, определяющих ее структуру (данные) и поведение (методы); инкапсуляция предназначена для изоляции контрактных обязательств абстракции (протокол/интерфейс) от их реализации.};
\item \nom{Наследование}{(англ. inheritance) — концепция объектно-ориентированного программирования, согласно которой абстрактный тип данных может наследовать данные и функциональность некоторого существующего типа, способствуя повторному использованию компонентов программного обеспечения.};
\item \nom{Полиморфизм }{это возможность объектов с одинаковой спецификацией иметь различную реализацию};
\item \nom{Полиморфизм }{это возможность объектов с одинаковой спецификацией иметь различную реализацию};
\end{itemize}
\subsection{Классы и объекты, поля и методы, статика}
@ -157,7 +157,7 @@ Cat2 named: Murzik is Black has age: 6
\item Сначала создается переменная, имеющая интересующий нас тип, в неё возможно записать ссылку на объект;
\item затем необходимо выделить память под объект;
\item создать и положить объект в выделенную часть памяти;
\item и сохранить ссылку на этот объект в памяти -- в переменную.
\item и сохранить ссылку на этот объект в памяти - в нашу переменную.
\end{itemize}
Для непосредственного создания объекта применяется оператор \code{new}, который динамически резервирует память под объект и возвращает ссылку на него, в общих чертах эта ссылка представляет собой адрес объекта в памяти, зарезервированной оператором \code{new}.
@ -176,7 +176,7 @@ Cat2 named: Murzik is Black has age: 6
[квалификаторы] ИмяКласса имяПеременной = \textbf{\code{new}} ИмяКласса();
\end{frm}
Оператор \code{new} динамически выделяет память для нового объекта, общая форма применения этого оператора имеет вид как на врезке выше, но на самом деле справа -- не имя класса, конструкция ИмяКласса() в правой части выполняет вызов конструктора данного класса, который подготавливает вновь создаваемый объект к работе.
Оператор \code{new} динамически выделяет память для нового объекта, общая форма применения этого оператора имеет вид как на врезке выше, но на самом деле справа - не имя класса, конструкция ИмяКласса() в правой части выполняет вызов конструктора данного класса, который подготавливает вновь создаваемый объект к работе.
Именно от количества применений оператора \code{new} будет зависеть, сколько именно объектов будет создано в программе.
@ -210,16 +210,16 @@ Cat2 named: Murzik is Black has age: 6
\end{verbatim}
\begin{frm}\info
Множественные ссылки на один и тот же объект в памяти довольно легко себе представить как ярлыки для запуска одной и той же программы на рабочем столе и в меню быстрого запуска. Или если на один и тот же шкафчик в раздевалке наклеить два номера -- сам шкафчик можно будет найти по двум ссылкам на него.
Множественные ссылки на один и тот же объект в памяти довольно легко себе представить как ярлыки для запуска одной и той же программы на рабочем столе и в меню быстрого запуска. Или если на один и тот же шкафчик в раздевалке наклеить два номера - сам шкафчик можно будет найти по двум ссылкам на него.
\end{frm}
Важно всегда перепроверять, какие объекты созданы, а какие имеют множественные ссылки.
\subsubsection{Методы}
Ранее было сказано о том, что в языке Java любая программа состоит из классов и функций, которые могут описываться только внутри них. Именно поэтому все функции в языке Java являются методами. А метод -- это функция, являющаяся частью некоторого класса, которая может выполнять операции над данными этого класса.
Ранее было сказано о том, что в языке Java любая программа состоит из классов и функций, которые могут описываться только внутри них. Именно поэтому все функции в языке Java являются методами. А метод - это функция, являющаяся частью некоторого класса, которая может выполнять операции над данными этого класса.
\begin{frm} \info
Метод -- это функция, принадлежащая классу
Метод - это функция, принадлежащая классу
\end{frm}
Метод для своей работы может использовать поля объекта и/или класса, в котором определен, напрямую, без необходимости передавать их во входных параметрах. Это похоже на использование глобальных переменных в функциях, но в отличие от глобальных переменных, метод может получать прямой доступ только к членам класса. Самые простые методы работают с данными объектов. Методы чаще всего формируют API классов, то есть способ взаимодействия с классами, интерфейс. Место методов во взаимодействии классов и объектов показано на рис. \hrf{pic:class-obj-nostatic}.
@ -330,7 +330,7 @@ public class Cat {
}
\end{lstlisting}
Помимо того, что статические поля -- это полезный инструмент создания общих свойств это ещ§ и опасный инструмент создания общих свойств. Так, например, мы знаем, что у котов четыре лапы, а не 6 и не 8. Не создавая никакого барсика будет понятно, что у кота -- 4 лапы. Это полезное поведение.
Помимо того, что статические поля - это полезный инструмент создания общих свойств это ещ§ и опасный инструмент создания общих свойств. Так, например, мы знаем, что у котов четыре лапы, а не 6 и не 8. Не создавая никакого барсика будет понятно, что у кота - 4 лапы. Это полезное поведение.
лайвкод 03-статическое-поле-ошибка Посмотрим на опасность. Мы видим, что у каждого кота есть имя, и помним, что коты хранят значение своего имени каждый сам у себя. А знают экземпляры о названии поля потому что знают, какого класса они экземпляры. Но что если мы по невнимательности добавим свойство статичности к имени кота?
@ -390,7 +390,7 @@ public class Cat {
\begin{itemize}
\item Young Generation — область где размещаются недавно созданные объекты. Когда она заполняется, происходит быстрая сборка мусора;
\item Old (Tenured) Generation — здесь хранятся долгоживущие объекты. Когда объекты из Young Generation достигают определенного порога «возраста», они перемещаются в Old Generation;
\item Permanent Generation — эта область содержит метаинформацию о классах и методах приложения, но начиная с Java 8 данная область памяти была упразднена. В Java 8 Permanent Generation заменён на Metaspace -- его динамически изменяемый по размеру аналог. Именно здесь находятся статические поля.
\item Permanent Generation — эта область содержит метаинформацию о классах и методах приложения, но начиная с Java 8 данная область памяти была упразднена. В Java 8 Permanent Generation заменён на Metaspace - его динамически изменяемый по размеру аналог. Именно здесь находятся статические поля.
\end{itemize}
Особенности кучи:
\begin{itemize}
@ -416,7 +416,7 @@ public class Cat {
Поскольку это довольно сложный процесс и может повлиять на производительность всего приложения, он реализован весьма разумно. Для этого используется так называемый процесс «Mark and Sweep» (отмечай и подметай). Java анализирует переменные из стека и «отмечает» все объекты, которые необходимо поддерживать в рабочем состоянии. Затем все неиспользуемые объекты очищаются. Фактически, чем больше мусора и чем меньше объектов помечены как живые, тем быстрее идет процесс. Чтобы сделать это еще более оптимизированным, память кучи состоит из нескольких частей.
\begin{enumerate}
\item Молодое поколение -- Все новые объекты начинаются с молодого поколения. Как только они выделены в коде Java, они попадают в этот подраздел, называемый \textbf{eden space}. В конце концов пространство эдема заполняется объектами. На этом этапе происходит незначительная сборка мусора, так называемая minor collection. Некоторые объекты (те, на которые есть ссылки) помечаются, а некоторые (те, на которые нет ссылок) -- нет. Те, которые были отмечены, затем переходят в другой подраздел молодого поколения под названием пространство выживших (само пространство выживших разделено на две части). Те, которые остались немаркированными, удаляются автоматической сборкой мусора.
\item Молодое поколение -- Все новые объекты начинаются с молодого поколения. Как только они выделены в коде Java, они попадают в этот подраздел, называемый \textbf{eden space}. В конце концов пространство эдема заполняется объектами. На этом этапе происходит незначительная сборка мусора, так называемая minor collection. Некоторые объекты (те, на которые есть ссылки) помечаются, а некоторые (те, на которые нет ссылок) - нет. Те, которые были отмечены, затем переходят в другой подраздел молодого поколения под названием пространство выживших (само пространство выживших разделено на две части). Те, которые остались немаркированными, удаляются автоматической сборкой мусора.
\item Выжившее поколение -- Так будет продолжаться до тех пор, пока пространство eden снова не заполнится; на этом этапе начинается новый цикл. События minor collection повторяются, но в этом цикле все отмеченные объекты, которые выживают как из пространства eden, так и из S0, фактически попадают во вторую часть пространства survivor, называемую S1.
\item Третье поколение -- Любые объекты, попадающие в пространство выживших, помечаются счетчиком возраста. Алгоритм проверяет этот счётчик, чтобы увидеть, соответствует ли он пороговому значению для перехода в старое поколение. Главная мысль в том, что объекты не обязательно переходят из S0 в S1 пространства выживших. На самом деле, они просто чередуются с тем, куда они переключаются при каждой minor сборке мусора.
@ -436,7 +436,7 @@ public class Cat {
\begin{frm}\info Следует отметить, что, поскольку этот GC является параллельным, вызов явной сборки мусора, такой как использование System.gc() во время работы параллельного процесса, приведет к сбою или прерыванию параллельного режима;
\end{frm}
\item Сборщик мусора G1. Сборщик мусора G1 (Garbage First) предназначен для приложений, работающих на многопроцессорных компьютерах с большим объемом памяти. Он доступен с обновления 4 JDK7 и в более поздних версиях. Сборщик G1 заменит сборщик CMS, поскольку он более эффективен;
\item Z сборщик мусора. ZGC (Z Garbage Collector) -- это масштабируемый сборщик мусора с низкой задержкой, который дебютировал в Java 11 в качестве экспериментального варианта для Linux. JDK 14 представил ZGC под операционными системами Windows и macOS. ZGC получил статус production начиная с Java 15.
\item Z сборщик мусора. ZGC (Z Garbage Collector) - это масштабируемый сборщик мусора с низкой задержкой, который дебютировал в Java 11 в качестве экспериментального варианта для Linux. JDK 14 представил ZGC под операционными системами Windows и macOS. ZGC получил статус production начиная с Java 15.
\end{enumerate}
Итоги рассмотрения устройства памяти
@ -457,7 +457,7 @@ public class Cat {
\subsection{Конструкторы}
\subsubsection{Контроль над созданием объекта}
Чтобы создать объект мы тратим одну строку кода \code{Cat cat1 = new Cat();} поля этого объекта заполнятся автоматически значениями по-умолчанию (числовые -- 0, логические -- \code{false}, ссылочные -- \code{null}). Часто нужно при создании дать коту какое-то имя, указать его возраст и цвет, поэтому пишем ещё три строки кода.
Чтобы создать объект мы тратим одну строку кода \code{Cat cat1 = new Cat();} поля этого объекта заполнятся автоматически значениями по-умолчанию (числовые - 0, логические - \code{false}, ссылочные - \code{null}). Часто нужно при создании дать коту какое-то имя, указать его возраст и цвет, поэтому пишем ещё три строки кода.
\begin{frm} \excl В таком подходе есть несколько недостатков:
\begin{enumerate}
@ -468,7 +468,7 @@ public class Cat {
Было бы неплохо иметь возможность сразу, при создании объекта указывать значения его полей. Для инициализации объектов при создании в Java предназначены конструкторы.
\begin{frm} \info Конструктор -- это частный случай метода в том смысле, что он тоже выполняет какие-то действия. Имя конструктора обязательно должно совпадать с именем класса, возвращаемое значение не пишется.
\begin{frm} \info Конструктор - это частный случай метода в том смысле, что он тоже выполняет какие-то действия. Имя конструктора обязательно должно совпадать с именем класса, возвращаемое значение не пишется.
\end{frm}
Если создать конструктор класса Cat, как показано в листинге \hrf{lst:construct-bad}, он автоматически будет вызываться при создании объекта. Теперь, при создании объектов класса Cat, все коты будут иметь одинаковые имена, цвет и возраст (это будут белые двухлетние Барсики).
@ -552,9 +552,9 @@ public class Cat {
Ключевое слово \code{this} сошлётся на вызвавший объект, в результате чего (в листинге \hrf{lst:constr-this})имя котика через конструктор будет установлено создаваемому объекту. Таким образом, здесь \code{this} позволяет не вводить новые переменные для обозначения одного и того же, что позволяет сделать код менее перегруженным дополнительными переменными.
Второй случай частого использования \code{this} с конструкторами -- вызов одного конструктора из другого. это может пригодиться когда в классе описано несколько конструкторов и не хочется в новом конструкторе переписывать код инициализации, приведенный в конструкторе ранее\footnote{один из базовых принципов программирования -- DRY (от англ dry -- чистый, сухой, акроним don't repeat yourself) -- не повторяйся. Его антагонист WET (от англ wet -- влажный, акроним write everything twice) -- пиши всё дважды.}. В листинге \hrf{lst:constr-this} вызывается обычный конструктор с тремя параметрами, который принимает имя цвет и возраст, но, допустим, когда котята рождаются возраст им задавать смысла нет, поэтому, может пригодиться и конструктор просто с именем и цветом, а зачем писать присваивание имени и цвета несколько раз, если можно вызвать соответствующий конструктор?
Второй случай частого использования \code{this} с конструкторами - вызов одного конструктора из другого. это может пригодиться когда в классе описано несколько конструкторов и не хочется в новом конструкторе переписывать код инициализации, приведенный в конструкторе ранее\footnote{один из базовых принципов программирования - DRY (от англ dry - чистый, сухой, акроним don't repeat yourself) - не повторяйся. Его антагонист WET (от англ wet - влажный, акроним write everything twice) - пиши всё дважды.}. В листинге \hrf{lst:constr-this} вызывается обычный конструктор с тремя параметрами, который принимает имя цвет и возраст, но, допустим, когда котята рождаются возраст им задавать смысла нет, поэтому, может пригодиться и конструктор просто с именем и цветом, а зачем писать присваивание имени и цвета несколько раз, если можно вызвать соответствующий конструктор?
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:constr-this},caption={Использование ключевого слова \code{this} для параметров}]
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:constr-this-constr},caption={Использование ключевого слова \code{this} для конструктора}]
public class Cat {
String name;
String color;
@ -579,7 +579,7 @@ public class Cat {
\begin{frm} \info Ключевое слово \code{this} в Java используется только в составе экземпляра класса. Но неявно ключевое слово \code{this} передается во все методы, кроме статических (поэтому \code{this} часто называют неявным параметром) и может быть использовано для обращения к объекту, вызвавшему метод.
\end{frm}
Существует ещё один вид конструктора -- это \textbf{конструктор копирования}. Чтобы создать конструктор копирования, возможно объявить конструктор, который принимает объект того же типа, в нашем случае котика, в качестве параметра, а в самом конструкторе аналогично конструктору, заполняющему все параметры, заполнить каждое поле входного объекта в новый экземпляр.
Существует ещё один вид конструктора - это \textbf{конструктор копирования}. Чтобы создать конструктор копирования, возможно объявить конструктор, который принимает объект того же типа, в нашем случае котика, в качестве параметра, а в самом конструкторе аналогично конструктору, заполняющему все параметры, заполнить каждое поле входного объекта в новый экземпляр.
\begin{lstlisting}[language=Java,style=JCodeStyle]
public Cat (Cat cat) {
@ -604,10 +604,10 @@ public Cat (Cat cat) {
Инкапсуляция связывает данные с манипулирующим ими кодом и позволяет управлять доступом к членам класса из отдельных частей программы, предоставляя доступ только с помощью определенного ряда методов, что позволяет предотвратить злоупотребление этими данными. То есть класс должен представлять собой «черный ящик», которым возможно пользоваться, но его внутренний механизм защищен от повреждений.
\begin{frm}\info
\textbf{Инкапсуляция} -- (англ. encapsulation, от лат. in capsula) -- в информатике, процесс разделения элементов абстракций, определяющих ее структуру (данные) и поведение (методы); инкапсуляция предназначена для изоляции контрактных обязательств абстракции (протокол/интерфейс) от их реализации.
\textbf{Инкапсуляция} - (англ. encapsulation, от лат. in capsula) в информатике, процесс разделения элементов абстракций, определяющих ее структуру (данные) и поведение (методы); инкапсуляция предназначена для изоляции контрактных обязательств абстракции (протокол/интерфейс) от их реализации.
\end{frm}
В Java в роли чёрного ящика выступает класс. Класс содержит в себе и данные (поля класса), и действия (методы класса) для работы с этими данными. Все члены класса в языке Java -- поля и методы -- имеют модификаторы доступа. Ранее уже было описан модификатор \code{public}, означающий доступность отовсюду, обычно используется для методов.
В Java в роли чёрного ящика выступает класс. Класс содержит в себе и данные (поля класса), и действия (методы класса) для работы с этими данными. Все члены класса в языке Java - поля и методы - имеют модификаторы доступа. Ранее уже было описан модификатор \code{public}, означающий доступность отовсюду, обычно используется для методов.
\begin{frm} \info Модификаторы доступа позволяют задать допустимую область видимости для членов класса, то есть контекст, в котором можно употреблять данную переменную или метод.
\end{frm}
@ -618,7 +618,7 @@ public Cat (Cat cat) {
\centering
\includesvg[scale=1]{pics/jc-03-modifiers.svg}
\caption{Модификаторы доступа и их относительная область видимости}
\label{mod:items}
\label{mod:items-no-protect}
\end{figure}
Модификатор \code{private} определяет доступность только внутри класса, и предпочтительнее всех.
@ -662,12 +662,12 @@ public class Cat {
Важно, что создавая для класса геттеры и сеттеры не только появляется возможность дополнять установке и возвращению значений полей дополнительную логику, но и возможность регулировать доступ к полям. Например, если в программе нужно запретить менять котикам окрас, то для класса просто не пишется соответствующий сеттер.
Внимательно осмотрев класс кота возможно прийти к выводу, что хранить возраст котов очень неудобно, потому что каждый год нужно будет обновлять это значение для каждого объекта кота в программе, а это может оказаться утомительно. Выходом может оказаться хранение не возраста, а неизменяемого параметра -- даты рождения и подсчёт возраста каждый раз, когда его запрашивают, ведь человеку, который запрашивает возраст кота, не интересно, каким образом получено значение, прочитано из поля или вычислено, ему важен конечный результат. Это и есть инкапсуляция, сокрытие реализации.
Внимательно осмотрев класс кота возможно прийти к выводу, что хранить возраст котов очень неудобно, потому что каждый год нужно будет обновлять это значение для каждого объекта кота в программе, а это может оказаться утомительно. Выходом может оказаться хранение не возраста, а неизменяемого параметра - даты рождения и подсчёт возраста каждый раз, когда его запрашивают, ведь человеку, который запрашивает возраст кота, не интересно, каким образом получено значение, прочитано из поля или вычислено, ему важен конечный результат. Это и есть инкапсуляция, сокрытие реализации.
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Перечислите модификаторы доступа
\item Инкапсуляция -- это
\item Инкапсуляция - это
\begin{enumerate}
\item архивирование проекта
\item сокрытие информации о классе
@ -677,7 +677,7 @@ public class Cat {
\subsection{Наследование}
\subsubsection{Проблема}
Второй кит ООП после инкапсуляции -- наследование.
Второй кит ООП после инкапсуляции - наследование.
Представим, что есть необходимость создать помимо класса котиков, класс собачек. Данный класс будет выглядеть очень похожим образом, только он будет не мяукать, а гавкать, и заменим обоим животным прыжок на простое перемещение на лапках.
@ -780,7 +780,7 @@ public class Dog {
\begin{frm} \info Наследование (англ. inheritance) — концепция объектно-ориентированного программирования, согласно которой абстрактный тип данных может наследовать данные и функциональность некоторого существующего типа, способствуя повторному использованию компонентов программного обеспечения.
\end{frm}
Наследование в Java реализуется ключевым словом \code{extends} (англ. -- расширять). И кот и пёс являются животными, у всех описываемых в программе животных есть имя, возраст, окрас, все описываемые животные могут бегать, прыгать, и откликаться на имя. Создав так называемый \textbf{родительский класс}, или суперкласс (листинг \hrf{lst:animal-fields}), и поместив в него поля, геттеры и сеттеры, стало возможным убрать поля, геттеры и сеттеры из кота и пса. Если полей много, лаконичность описания родственных классов может быть весьма ощутимой.
Наследование в Java реализуется ключевым словом \code{extends} (англ. - расширять). И кот и пёс являются животными, у всех описываемых в программе животных есть имя, возраст, окрас, все описываемые животные могут бегать, прыгать, и откликаться на имя. Создав так называемый \textbf{родительский класс}, или суперкласс (листинг \hrf{lst:animal-fields}), и поместив в него поля, геттеры и сеттеры, стало возможным убрать поля, геттеры и сеттеры из кота и пса. Если полей много, лаконичность описания родственных классов может быть весьма ощутимой.
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:animal-fields},caption={Класс животного}]
public class Animal {
@ -859,9 +859,9 @@ public class Cat extends Animal {
То есть, к членам данных и методам класса можно применять следующие модификаторы доступа
\begin{itemize}
\item \code{private} -- содержимое класса доступно только из методов данного класса;
\item \code{public} -- есть доступ фактически отовсюду;
\item default (по-умолчанию) -- содержимое класса доступно из любого места пакета, в котором этот класс находится;
\item \code{private} - содержимое класса доступно только из методов данного класса;
\item \code{public} - есть доступ фактически отовсюду;
\item default (по-умолчанию) - содержимое класса доступно из любого места пакета, в котором этот класс находится;
\item \code{protected} (защищенный доступ) содержимое доступно также как с модификатором по-умолчанию, но ещё и для классов-наследников.
\end{itemize}
@ -875,12 +875,12 @@ public class Cat extends Animal {
То есть верным вариантом в листинге \hrf{lst:animal-fields} будет применение модификатора \code{protected}.
\subsubsection{Конструкторы в наследовании}
\begin{frm} \excl Несмотря на то, что конструктор -- это частный случай метода, если перенести одинаковые конструкторы кота и пса в общий класс животного, программа снова перестанет работать, потому что важно учитывать механику вызова конструкторов при наследовании.
\begin{frm} \excl Несмотря на то, что конструктор - это частный случай метода, если перенести одинаковые конструкторы кота и пса в общий класс животного, программа снова перестанет работать, потому что важно учитывать механику вызова конструкторов при наследовании.
\end{frm}
Важно запомнить, что при создании любого объекта в первую очередь вызывается конструктор его базового (родительского) класса, а только потом — конструктор самого класса, объект которого мы создаем. То есть при создании объекта \code{Cat} сначала отработает конструктор класса \code{Animal}, а только потом конструктор \code{Cat}. Но, поскольку конструктор по-умолчанию в нашем случае перестал создаваться, а других может быть бесконечно много, это создало неопределённость, которую программа разрешить не может.
При описании класса, можно явно вызвать конструктор базового класса в конструкторе класса-потомка. Базовый класс еще называют «суперклассом», поэтому в Java для его обозначения используется ключевое слово \code{super}. Здесь такое же ограничение, как и при вызове конструкторов данного класса (через \code{this}) -- вызов такого конструктора может быть только один и быть только первой строкой. Таким образом, код, для всех животных в программе будет выглядеть следующим образом:
При описании класса, можно явно вызвать конструктор базового класса в конструкторе класса-потомка. Базовый класс еще называют «суперклассом», поэтому в Java для его обозначения используется ключевое слово \code{super}. Здесь такое же ограничение, как и при вызове конструкторов данного класса (через \code{this}) - вызов такого конструктора может быть только один и быть только первой строкой. Таким образом, код, для всех животных в программе будет выглядеть следующим образом:
\begin{multicols}{2}
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:animal-full},caption={Класс животного}]
@ -975,7 +975,7 @@ public class Bird extends Animal {
\begin{frm} \excl Множественное наследование запрещено! Для каждого создаваемого подкласса можно указать только один суперкласс. В Java не поддерживается множественное наследование, то есть наследование одного класса от нескольких суперклассов. Зато возможно каскадное наследование, то есть класс-наследник вполне может быть чьим-то родителем.
\end{frm}
Если класс-родитель не указан, таковым считается класс \code{Object}. Таким образом можно сделать вывод о том, что любой класс в джава так или иначе -- наследник \code{Object} и, соответственно, всех его свойств и методов. Объект подкласса представляет объект суперкласса, выражаясь проще, возможно ко всем котикам обращаться через общее название Животное, и ко всем объектам в программе возможно обратиться через класс \code{Object}. Поэтому в программе не будет ошибкой написать подобный код:
Если класс-родитель не указан, таковым считается класс \code{Object}. Таким образом можно сделать вывод о том, что любой класс в джава так или иначе - наследник \code{Object} и, соответственно, всех его свойств и методов. Объект подкласса представляет объект суперкласса, выражаясь проще, возможно ко всем котикам обращаться через общее название Животное, и ко всем объектам в программе возможно обратиться через класс \code{Object}. Поэтому в программе не будет ошибкой написать подобный код:
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:obj},caption={}]
Object animal = new Animal("Cat", "Black", 3);
Object cat = new Cat("Murka", "Black", 4);
@ -1022,7 +1022,7 @@ if (cat instanceof Dog) {
Абстрактный класс — это написанная максимально широкими мазками, приблизительная «заготовка» для группы будущих классов. Эту заготовку нельзя использовать в чистом виде — слишком «сырая». Но она описывает некое общее состояние и поведение, которым будут обладать будущие классы — наследники абстрактного класса.
Абстрактными могут быть не только классы, но и методы. \textbf{Абстрактный метод} -- это метод без реализации. Все животные в примерах выше умеют издавать свой звук. Известно, на этапе проектирования животного, что все животные должны издавать звук, но невозможно сказать, какой именно. Поэтому, определяется, что у животного есть метод издать звук, но реализация этого метода в животном не пишется, слишком мало сведений. Поэтому, метод помечается как абстрактный.
Абстрактными могут быть не только классы, но и методы. \textbf{Абстрактный метод} - это метод без реализации. Все животные в примерах выше умеют издавать свой звук. Известно, на этапе проектирования животного, что все животные должны издавать звук, но невозможно сказать, какой именно. Поэтому, определяется, что у животного есть метод издать звук, но реализация этого метода в животном не пишется, слишком мало сведений. Поэтому, метод помечается как абстрактный.
Что будет, если программа попытается вызвать метод \code{voice()} у животного?
@ -1030,8 +1030,8 @@ if (cat instanceof Dog) {
\begin{frm} \info
\begin{itemize}
\item Абстрактный метод -- это метод не содержащий реализации (объявление метода).
\item Абстрактный класс -- класс содержащий хотя бы один абстрактный метод.
\item Абстрактный метод - это метод не содержащий реализации (объявление метода).
\item Абстрактный класс - класс содержащий хотя бы один абстрактный метод.
\item Абстрактный класс нельзя инстанциировать (создать экземпляр).
\end{itemize}
\end{frm}
@ -1046,7 +1046,7 @@ if (cat instanceof Dog) {
\item extends
\item как в С++, используется двоеточие
\end{enumerate}
\item super -- это
\item super - это
\begin{enumerate}
\item ссылка на улучшенный класс
\item ссылка на расширенный класс
@ -1065,7 +1065,7 @@ if (cat instanceof Dog) {
Вынесем последний оставшийся в котиках и птичках метод в общий класс животного. В классах-потомках определим такие же методы, как и объявленный метод класса родителя, который хотим изменить.
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:cmpcat3},caption={Класс кота}]
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:cmpcat4},caption={Класс кота}]
public abstract class Animal {
// ...
@ -1134,9 +1134,9 @@ public class Cat extends Animal {
\begin{frm} \info Полиморфизм в языках программирования и теории типов — способность функции обрабатывать данные разных типов. Выделяют параметрический полиморфизм и ad-hoc-полиморфизм.
\end{frm}
Широко распространено определение полиморфизма, приписываемое Бьёрну Страуструпу: «один интерфейс — много реализаций». Полиморфизм -- это гораздо более широкое понятие, чем просто переопределение методов, в эту тему завязаны разные интересные теории типов и информации, множество парадигм программирования и другое. С утилитарной точки зрения, остался ещё один вариант, который, тем не менее, не дотягивает до истинного полиморфизма.
Широко распространено определение полиморфизма, приписываемое Бьёрну Страуструпу: «один интерфейс — много реализаций». Полиморфизм - это гораздо более широкое понятие, чем просто переопределение методов, в эту тему завязаны разные интересные теории типов и информации, множество парадигм программирования и другое. С утилитарной точки зрения, остался ещё один вариант, который, тем не менее, не дотягивает до истинного полиморфизма.
\begin{frm} \info К полиморфизму также относится перегрузка методов (Overloading) -- использование более одного метода с одним и тем же именем, но с разными параметрами в одном и том же классе или между суперклассом и подклассами. \end{frm}
\begin{frm} \info К полиморфизму также относится перегрузка методов (Overloading) - использование более одного метода с одним и тем же именем, но с разными параметрами в одном и том же классе или между суперклассом и подклассами. \end{frm}
Перегрузка работает также, как работала без явной привязки кода к парадигме ООП, ничего нового, но для порядка следует создать возможность животным перемещаться не только абстрактно, но и на какое-то конкретное место или на какое-то конкретное количество шагов.

View File

@ -1,7 +1,7 @@
\documentclass[j-spec.tex]{subfiles}
\begin{document}
\setcounter{section}{2}
\setcounter{section}{3}
\setlength{\columnsep}{22pt}
\pagestyle{plain}
\sloppy
@ -13,65 +13,106 @@
\subsection{В этом разделе}
В дополнение к предыдущему, будут разобраны такие понятия, как внутренние и вложенные классы; процессы создания, использования и расширения перечислений. Более детально будет разобрано понятие исключений и их тесная связь с многопоточностью в Java. Будут рассмотрены исключения с точки зрения ООП, процесс обработки исключений.
\begin{itemize}
\item \nom{Внутренний класс}{ };
\item \nom{Вложенный класс}{ };
\item \nom{Исключение}{ };
\item \nom{Многопоточность}{ };
\item \nom{Перечисление}{это упоминание объектов, объединённых по какому-либо признаку. Фактически, представляет новый тип данных, поэтому возможно определить переменную данного типа и использовать её.};
\item \nom{Внутренний класс}{нестатический класс, объявленный внутри другого класса.};
\item \nom{Вложенный класс}{статический класс, объявленный внутри другого класса.};
\item \nom{Локальный класс}{класс, объявленный внутри минимального блока кода другого класса, чаще всего, метода.};
\item \nom{Исключение}{это отступление от общего правила, несоответствие обычному порядку вещей.};
\item \nom{Многопоточность}{одновременное выполнение двух или более потоков для максимального использования центрального процессора (CPU -- central processing unit). Каждый поток работает параллельно и имеет свою собственную выделенную стековую память.};
\end{itemize}
\subsection{Перечисления}
Кроме восьми примитивных типов данных и классов в Java есть специальный тип, выведенный на уровень синтаксиса языка - \code{enum} или перечисление. Перечисления представляют набор логически связанных констант. Объявление перечисления происходит с помощью оператора \code{enum}, после которого идет название перечисления. Затем идет список элементов перечисления через запятую.
Кроме восьми примитивных типов данных и классов в Java есть специальный тип, выведенный на уровень синтаксиса языка -- \code{enum} или перечисление. Перечисления представляют набор логически связанных констант. Объявление перечисления происходит с помощью оператора \code{enum}, после которого идет название перечисления. Затем идет список элементов перечисления через запятую.
\begin{frm} \info Перечисление -- это упоминание объектов, объединённых по какому-либо признаку \end{frm}
Перечисления -- это специальные классы, содержащие внутри себя собственные статические экземпляры.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Пример перечисления}]
enum Season { WINTER, SPRING, SUMMER, AUTUMN }.
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
\end{lstlisting}
Когда мы доберёмся до рассмотрения внутренних и вложенных классов, в том числе статических, дополнительно это проговорим.
Перечисление фактически представляет новый тип данных, поэтому мы можем определить переменную данного типа и использовать её. Переменная типа перечисления может хранить любой объект этого исключения.
Перечисление, фактически, представляет новый тип данных, поэтому возможно определить переменную данного типа и использовать её. Переменная типа перечисления может хранить любой объект этого исключения.
Season current = Season.SPRING; System.out.println(current);
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Переменная типа перечисления}]
Season current = Season.SPRING;
System.out.println(current);
\end{lstlisting}
Интересно также то, что вывод в терминал и запись в коде у исключений полностью совпадают, поэтому, в терминале мы видим ....
Интересно также то, что вывод в терминал и запись в коде у исключений полностью совпадают, поэтому, в результате выполнения этого кода, в терминале будет выведено
Каждое перечисление имеет статический метод values(). Он возвращает массив всех констант перечисления, далее мы можем этим массивом манипулировать как нам нужно, например, вывести на экран все его элементы.
\begin{verbatim}
SPRING
\end{verbatim}
Season[] seasons = Season.values(); for (Season s : seasons) { System.out.printf("s ", s); }
Каждое перечисление имеет статический метод \code{values()}, возвращающий массив всех констант перечисления.
Именно в этом примере, я использую цикл foreach для прохода по массиву, для лаконичности записи. Чуть подробнее о его особенностях мы поговорим на одной из следующих лекций. Если коротко, данный цикл возьмёт последовательно каждый элемент перечисления, присвоит ему имя s точно также, как мы это делали в примере на две строки выше, и сделает эту переменную С доступной в теле цикла в рамках одной итерации, на следующей итерации будет взят следующий элемент, и так далее
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Вывод всех элементов перечисления}]
Season[] seasons = Season.values();
for (Season s : seasons) {
System.out.printf("s ", s);
}
\end{lstlisting}
% +++ Комментатор_Ильнар. Строго говоря не очень корректная фраза "потому что у перечислений нет индексов". seasons - это уже обычный массив и можно его обойти обычным способом с индексами, скорее мы просто тут показали foreach цикл.
Именно в этом примере используется цикл foreach для прохода по массиву, для лаконичности записи. Данный цикл берёт последовательно каждый элемент перечисления, присваивает ему имя \code{s} точно также, как это сделано в примере выше, делает эту переменную доступной в теле цикла в рамках одной итерации, на следующей итерации будет взят следующий элемент, и так далее.
Также в перечисления встроен метод ordinal() возвращающий порядковый номер определенной константы (нумерация начинается с 0).
\begin{verbatim}
WINTER, SPRING, SUMMER, AUTUMN
\end{verbatim}
System.out.println(current.ordinal())
Также, в перечисления встроен метод \code{ordinal()}, возвращающий порядковый номер определенной константы (нумерация начинается с 0). Обратите внимание на синтаксис, метод можно вызвать только у конкретного экземпляра перечисления, а при попытке вызова у самого класса перечисления, ожидаемо компилятор выдаёт ошибку невозможности вызова нестатического метода из статического контекста.
Обратите внимание на синтаксис, метод можно вызвать только у конкретного экземпляра перечисления, а при попытке вызова у самого класса перечисления
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Метод \code{ordinal()}}]
System.out.println(current.ordinal());
System.out.println(Seasons.ordinal())
System.out.println(Seasons.ordinal()); // <@\lh{dkgreen}{ошибка}@>
\end{lstlisting}
мы ожидаемо получаем ошибку невозможности вызова нестатического метода из статического контекста.
Такое поведение возможно, только если номер элемента хранится в самом объекте.
как мы с вами помним из пояснения связи классов и объектов, такое поведение возможно только если номер элемента как-то хранится в самом объекте. Мы видим в перечислениях очень примечательный пример инкапсуляции - мы не знаем, хранятся ли на самом деле объекты перечисления в виде массива, но можем вызвать метод вельюс. Мы не знаем, хранится ли в каждом объекте перечисления его номер, но можем вызвать его метод ординал. А раз перечисление - это класс, мы можем определять в нём поля, методы, конструкторы и прочее.
\begin{frm} \info
В перечислениях можно наблюдать очень примечательный пример инкапсуляции -- неизвестно, хранятся ли на самом деле объекты перечисления в виде массива, но можем вызвать метод values() и получить массив всех элементов перечисления. Неизвестно, хранится ли в каждом объекте перечисления его номер, но можем вызвать его метод \code{ordinal()}.
\end{frm}
Перечисление Color определяет приватное поле code для хранения кода цвета, а с помощью метода getCode оно возвращается.
Раз перечисление -- это класс, возможно определять в нём поля, методы, конструкторы и прочее. Перечисление \code{Color} определяет приватное поле \code{code} для хранения кода цвета, а с помощью метода \code{getCode} он возвращается.
enum Color {
RED("\#FF0000"), GREEN("\#00FF00"), BLUE("\#0000FF");
String code;
Color (String code) { this.code = code; }
String getCode() { return code; }
}
Через конструктор передается для него значение. Следует отметить, что конструктор по умолчанию приватный, то есть имеет модификатор private. Любой другой модификатор будет считаться ошибкой. Поэтому создать константы перечисления с помощью конструктора мы можем только внутри перечисления. И что косвенно намекает нам на то что объекты перечисления это статические объекты внутри самого класса перечисления. Также важно, что механизм описания конструкторов класса работает по той же логике, что и обычные конструкторы, то есть создав собственный конструктор мы уничтожили конструктор по-умолчанию, впрочем, мы его можем создать, если это будет иметь смысл для решаемой задачи.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Расширение объекта перечисления}]
public class Main {
enum Color {
RED("#FF0000"), BLUE("#0000FF"), GREEN("#00FF00");
private String code;
Color(String code) {
this.code = code;
}
Исходя из сказанного ранее можно сделать вывод, что с объектами перечисления можно работать точно также, как с обычными объектами, что мы и сделаем, например, выведя информацию о них в консоль
public String getCode(){ return code;}
}
for (Color c : Color.values()) { System.out.printf("s(s) ", c, c.getCode()); }
public static void main(String[] args) {
System.out.println(Color.RED.getCode());
System.out.println(Color.GREEN.getCode());
}
}
\end{lstlisting}
Через конструктор передается значение пользовательского поля.
\begin{frm} \excl Конструктор по умолчанию имеет модификатор \code{private}. Любой другой модификатор будет считаться ошибкой.
\end{frm}
Cоздать константы перечисления с помощью конструктора возможно только внутри самого перечисления. И что косвенно намекает на то, что объекты перечисления это статические объекты внутри самого класса перечисления. Также важно, что механизм описания конструкторов класса работает по той же логике, что и обычные конструкторы, то есть, при описании собственного конструктора, конструктор по-умолчанию перестаёт создаваться автоматически. Таким образом, с объектами перечисления можно работать точно также, как с обычными объектами.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Вывод значений пользовательского поля перечисления}]
for (Color c : Color.values()) {
System.out.printf("s(s)\n", c, c.getCode());
}
\end{lstlisting}
\begin{verbatim}
RED(#FF0000)
BLUE(#0000FF)
GREEN(#00FF00)
\end{verbatim}
\subsubsection{Задания для самопроверки}
\begin{enumerate}
@ -81,13 +122,13 @@ for (Color c : Color.values()) { System.out.printf("s(s) ", c, c.getCode()); }
\item вести учёт классов в программе;
\item вести учёт схожих по смыслу явлений в программе;
\end{enumerate}
\item Перечисление - это: 2
\item Перечисление -- это: 2
\begin{enumerate}
\item массив
\item класс
\item объект
\end{enumerate}
\item каждый объект в перечислении - это: 3
\item каждый объект в перечислении -- это: 3
\begin{enumerate}
\item статическое поле
\item статический метод
@ -95,85 +136,364 @@ for (Color c : Color.values()) { System.out.printf("s(s) ", c, c.getCode()); }
\end{enumerate}
\end{enumerate}
\subsection{Внутренние и вложенные классы}
В Java есть возможность создавать классы внутри других классов, все такие классы разделены на следующие типы:
\begin{enumerate}
\item Non-static nested (inner) classes — нестатические вложенные (внутренние) классы;
\begin{itemize}
\item локальные классы (local classes);
\item анонимные классы (anonymous classes);
\end{itemize}
\item Static nested classes — статические вложенные классы.
\end{enumerate}
Для рассмотрения анонимных классов понадобятся дополнительные знания об интерфейсах, поэтому будут рассмотрены позднее.
\subsubsection{Внутренние классы}
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Вывод значений пользовательского поля перечисления}]
public class Orange {
public void squeezeJuice() {
System.out.println("Squeeze juice ...");
}
class Juice {
public void flow() {
System.out.println("Juice dripped ...");
}
}
}
\end{lstlisting}
\textbf{Внутренние классы} создаются внутри другого класса. Рассмотрим на примере апельсина с реализацией, как это предлагает официальная документация Oracle. В основной программе необходимо создать отдельно апельсин, отдельно его сок через интересную форму вызова конструктора, показанную в листинге \hrf{lst:create-orange}, что позволяет работать как с апельсином, так и его соком по отдельности.
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:create-orange},caption={Обычный апельсин Oracle}]
Orange orange = new Orange();
Orange.Juice juice = orange.new Juice();
orange.squeezeJuice();
juice.flow();
\end{lstlisting}
Важно помнить, что когда в жизни апельсин сдавливается, из него сам по себе течёт сок, а когда апельсин попадает к нам в программу он сразу снабжается соком.
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:create-gb-orange},caption={Необычный апельсин GeekBrains}]
public class Orange {
private Juice juice;
public Orange() {
this.juice = new Juice();
}
public void squeezeJuice() {
System.out.println("Squeeze juice ...");
juice.flow();
}
private class Juice {
public void flow() {
System.out.println("Juice dripped ...");
}
}
}
\end{lstlisting}
Итак, был создан апельсин, при создании объекта апельсина у него сразу появляется сок. Ниже в классе описано потенциальное наличие у апельсина сока, как его части, поэтому внутри класса апельсин создан класс сока. При создании апельсина создали сок, так или иначе -- самостоятельную единицу, обладающую своими свойствами и поведением, отличным от свойств и поведения апельсина, но неразрывно с ним связанную. При попытке выдавить сок у апельсина -- объект сока сообщил о том, что начал течь
\begin{lstlisting}[language=Java,style=JCodeStyle,label={lst:use-gb-orange},caption={Использование апельсина GeekBrains}]
Orange orange = new Orange();
orange.squeezeJuice();
\end{lstlisting}
Таким образом у каждого апельсина будет свой собственный сок, который возможно выжать, сдавив апельсин. В этом смысл внутренних классов не статического типа -- нужные методы вызываются у нужных объектов.
\begin{frm} \info Такая связь объектов и классов называется композицией. Существуют также ассоциация и агрегация.
\end{frm}
Если класс полезен только для одного другого класса, то часто бывает удобно встроить его в этот класс и хранить их вместе. Использование внутренних классов увеличивает инкапсуляцию. Оба примера достаточно отличаются реализацией. Пример не из документации подразумевает «более сильную» инкапсуляцию, так как извне ко внутреннему классу доступ получить нельзя, поэтому создание объекта внутреннего класса происходит в конструкторе основного класса -- в апельсине. С другой стороны, у примера из документации есть доступ извне ко внутреннему классу сока, но всё равно, только через основной класс апельсина, как и создать объект сока можно только через объект апельсина, то есть подчёркивается взаимодействие на уровне объектов.
\textbf{Особенности внутренних классов}:
\begin{itemize}
\item Внутренний объект не существует без внешнего. Это логично -- для этого \code{Juice} был создан внутренним классом, чтобы в программе не появлялись апельсиновые соки из воздуха.
\item Внутренний объект имеет доступ ко всему внешнему. Код внутреннего класса имеет доступ ко всем полям и методам экземпляра (и к статическим членам) окружающего класса, включая все члены, даже объявленные как \code{private}.
\item Внешний объект не имеет доступа ко внутреннему без создания объекта. Это логично, так как экземпляров внутреннего класса может быть создано сколь угодно много, и к какому именно из них обращаться?
\item У внутренних классов есть модификаторы доступа. Это влияет на то, где в программе возможно создавать экземпляры внутреннего класса. Единственное сохраняющееся требование — объект внешнего класса тоже обязательно должен существовать и быть видимым.
\item Внутренний класс не может называться как внешний, однако, это правило не распространяется ни на поля, ни на методы;
\item Во внутреннем классе нельзя иметь не-final статические поля. Статические поля, методы и классы являются конструкциями верхнего уровня, которые не связаны с конкретными объектами, в то время как каждый внутренний класс связан с экземпляром окружающего класса.
\item Объект внутреннего класса нельзя создать в статическом методе «внешнего» класса. Это объясняется особенностями устройства внутренних классов. У внутреннего класса могут быть конструкторы с параметрами или только конструктор по умолчанию. Но независимо от этого, когда создаётся объект внутреннего класса, в него неявно передаётся ссылка на объект внешнего класса.
\item Со внутренними классами работает наследование и полиморфизм.
\end{itemize}
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Внутренний класс: 1
\begin{enumerate}
\item реализует композицию;
\item это служебный класс;
\item не требует объекта внешнего класса;
\end{enumerate}
\item Инкапсуляция с использованием внутренних классов: 2
\begin{enumerate}
\item остаётся неизменной
\item увеличивается
\item уменьшается
\end{enumerate}
\item Статические поля внутренних классов: 2
\begin{enumerate}
\item могут существовать
\item могут существовать только константными
\item не могут существовать
\end{enumerate}
\end{enumerate}
\subsubsection{Локальные классы}
Классы -- это новый тип данных для программы, поэтому технически возможно создавать классы, а также описывать их, например, внутри методов. Это довольно редко используется но синтаксически язык позволяет это сделать. \textbf{Локальные классы} — это подвид внутренних классов. Однако, у локальных классов есть ряд важных особенностей и отличий от внутренних классов. Главное заключается в их объявлении.
\begin{frm} \info Локальный класс объявляется только в блоке кода. Чаще всего — внутри какого-то метода внешнего класса.
\end{frm}
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Пример локального класса}]
public class Animal {
void performBehavior(boolean state) {
class Brain {
void sleep() {
if (state)
System.out.println("Sleeping");
else
System.out.println("Not sleeping");
}
}
Brain brain = new Brain();
brain.sleep();
}
}
\end{lstlisting}
Например, некоторое животное, у которого устанавливается состояние спит оно или нет. Метод \code{performBehavior()} принимает на вход булево значение и определяет, спит ли животное. Мог возникнуть вопрос: зачем? Итоговое решение об архитектуре проекта всегда зависит от структуры, сложности и предназначения программы.
\textbf{Особенности локальных классов}:
\begin{itemize}
\item Локальный класс сохраняет доступ ко всем полям и методам внешнего класса, а также ко всем константам, объявленным в текущем блоке кода, то есть полям и аргументам метода объявленным как \code{final}. Начиная с JDK 1.8 локальный класс может обращаться к любым полям и аргументам метода объявленным в текущем блоке кода, даже если они не объявлены как \code{final}, но только в том случае если их значение не изменяется после инициализации.
\item Локальный класс должен иметь свои внутренние копии всех локальных переменных, которые он использует (эти копии автоматически создаются компилятором). Единственный способ обеспечить идентичность значений локальной переменной и ее копии объявить локальную переменную как \code{final}.
\item Экземпляры локальных классов, как и экземпляры внутренних классов, имеют окружающий экземпляр, ссылка на который неявно передается всем конструкторам локальных классов. То есть, сперва должен быть создан экземпляр внешнего класса, а только затем экземпляр внутреннего класса.
\end{itemize}
\subsubsection{Статические вложенные классы}
При объявлении такого класса используется ключевое слово \code{static}. Для примера в классе котика % lst:cmpcat
и заменим метод \code{voice()} на статический класс.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Статический вложенный класс}]
public class Cat {
private String name;
private String color;
private int age;
public Cat()
public Cat(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
static class Voice {
private final int volume;
public Voice(int volume) {
this.volume = volume;
}
public void sayMur() {
System.out.printf("A cat purrs with volume %d\n", volume);
}
}
}
\end{lstlisting}
То есть, такое мурчание котика может присутствовать без видимости и понимания, что именно за котик присутствует в данный момент. Также, добавлена возможность установить уровень громкости мурчанья.
\begin{frm} \info
Основное отличие статических и нестатических вложенных классов в том, что объект статического класса не хранит ссылку на конкретный экземпляр внешнего класса.
\end{frm}
Без объекта внешнего класса объект внутреннего просто не мог существовать. Для статических вложенных классов это не так. Объект статического вложенного класса может существовать сам по себе. В этом плане статические классы более независимы, чем нестатические. Довольно важный момент заключается в том, что при создании такого объекта нужно указывать название внешнего класса,
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование статического класса}]
Cat.Voice voice = new Cat.Voice(100);
voice.sayMur();
\end{lstlisting}
Статический вложенный класс может обращаться только к статическим полям внешнего класса. При этом неважно, какой модификатор доступа имеет статическая переменная во внешнем классе.
Не следует путать объекты с переменными. Если речь идёт о статических переменных — да, статическая переменная класса существует в единственном экземпляре. Но применительно ко вложенному классу \code{static} означает лишь то, что его объекты не содержат ссылок на объекты внешнего класса.
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Вложенный класс: 1
\begin{enumerate}
\item реализует композицию;
\item это локальный класс;
\item всегда публичный;
\end{enumerate}
\item Статический вложенный классо бладает теми же свойствами, что: 2
\begin{enumerate}
\item константный метод
\item внутренний класс
\item статическое поле
\end{enumerate}
\end{enumerate}
\subsection{Исключения}
Язык программирования -- это, в первую очередь, набор инструментов. Например, есть художник. У художника есть набор всевозможных красок, кистей, холстов, карандашей, мольберт, ластик и прочие. Это всё его инструменты. Тоже самое для программиста. У программиста есть язык программирования, который предоставляет ему инструменты: циклы, условия, классы, функции, методы, ООП, фрейморки, библиотеки. Исключения -- это один из инструментов. Исключения всегда следует рассматривать как ещё один инструмент для работы программиста.
\begin{frm} \info Исключение -- это отступление от общего правила, несоответствие обычному порядку вещей
\end{frm}
В общем случае, возникновение исключительной ситуации, это ошибка в программе, но основным вопросом является следующий. Возникшая ошибка -- это:
\begin{itemize}
\item ошибка в коде программы;
\item ошибка в действиях пользователя;
\item ошибка в аппаратной части компьютера?
\end{itemize}
При возникновении ошибок создаётся объект класса «исключение», и в этот объект записывается какое-то максимальное количество информации о том, какая ошибка произошла, чтобы потом прочитать и понять, где проблема. Соответственно эти объекты возможно «ловить и обрабатывать».
\begin{figure}[H]
\fontsize{11}{1}\selectfont
\includesvg[scale=.85]{pics/jc-04-throwable.svg}
\caption{Часть иерархии исключений}
\label{pic:exception-hierarchy}
\end{figure}
Все исключения наследуются от класса \code{Throwable} и могут быть как обязательные к обработке, так и необязательные. Есть ещё подкласс \code{Error}, но он больше относится к аппаратным сбоям или серьёзным алгоритмическим или архитектурным ошибкам, и на данном этапе интереса не представляет, потому что поймав, например, \code{OutOfMemoryError} средствами Java прямо в программе с ним ничего сделать невозможно, такие ошибки необходимо обрабатывать и не допускать в процессе разработки ПО.
Для изучения и примеров, воспользуемся двумя подклассами \code{Throwable} -- \code{Exception} -- \code{RuntimeException} и \code{IOException}.
\begin{frm} \excl Все исключения, кроме наследников \code{RuntimeException} необходимо обрабатывать.
\end{frm}
% лайвкод 04-мартёшка-методов & Давайте рассмотрим примерчики, напишем пару-тройку методов, и сделаем матрёшку,
% из мэйна вызываем метод2, оттуда метод1, оттуда метод0, а в методе0 всё как всегда портим, пишем
% private static int div0() return 1 / 0;
% ArithmeticException является наследником класса RuntimeEcxeption поэтому статический анализатор его не подчеркнул, и ловить его вроде как не обязательно, спасибо большое разработчикам джава, надёжность кода не повысилась, единообразность работы всех исключений нарушилась, всё хорошо.\\ \hline
% лайвкод 04-метод-деления & Выходит, на примере деления на ноль можно всё хорошо сразу и объяснить. допустим у нас есть какой-то метод который возможно мы даже сами написали, который, скажем, целочисленно делит два целых числа. немного его абстрагируем
% private static int div0(int a, int b) return a / b;
% Если посмотреть на этот метод с точки зрения программирования, он написан очень хорошо - алгоритм понятен, метод с единственной ответственностью, всё супер. Однако, из поставленной перед методом задачи очевидно, что он не может работать при всех возможных входных значениях. То есть если у нас вторая переменная равна нулю, то это неправильно. И что же с этим делать? \\ \hline
% лайвкод 04-исключение-1 & Нам нужно как-то запретить пользователю передавать в качестве делителя ноль. Самое простое - ничего не делать, но мы так не можем.
% private static int div0(int a, int b)
% if (b != 0) return a / b; return ???;
% Потому что метод должен что-то вернуть, а что вернуть, неизвестно, ведь от нас ожидают результат деления. Поэтому, допустим можем руками сделать проверку (б == 0ф) и выкинуть пользователю так называемый объект исключения throw new RuntimeException("деление на ноль") а иначе вернём а / б.
% private static int div0(int a, int b)
% if (b == 0) throw new RuntimeException("parameter error");
% return a / b; \\ \hline
% лайвкод 04-исключение-2 & Вызываем метод и пробуем делить 1 на 2. А вот если мы второй параметр передадим 0 то у нас выкинется исключение,
% System.out.println(div0(1,2));
% System.out.println(div0(1,0));
% то есть по сути new... это конструктор, нового объекта какого-то класса, в который мы передаём какой то параметр, в данном конкретном случае это строка с сообщением. Зафиксируем пока что эту мысль. \\ \hline
% отбивка введение в многопоточность & Кажется многовато отступлений, но без этого точно никак нельзя продолжать. \\ \hline
% 04-метод-броска & Итак, что происходит? Ключевое слово throw заставляет созданный объект исключения начать свой путь по родительским методам, пока этот объект не встретится с каким-то обработчиком. в нашем текущем случае - это дефолтный обработчик виртуальной машины, который в специальный поток err выводит так называемый стектрейс, и завершает дальнейшее выполнение метода.\\ \hline
% 04-поток-ерр & Далее по порядку: поток ерр. Все программы в джава всегда многопоточны. Понимаете вы многопоточность или нет, знаете ли вы о её существовании или нет, не важно, многопоточность есть всегда. не будем вдаваться в сложности прикладной многопоточности, у нас ещё будет на это довольно много времени, пока что поговорим в общем. в чём смысл? смысл в том, что на старте программы запускаются так называемые потоки, которые работают псевдопараллельно и предназначены каждый для решения своих собственных задач, например, это основной поток, поток сборки мусора, поток обработчика ошибок, потоки графического интерфейса. Основная задача этих потоков - делать своё дело и иногда обмениваться информацией.\\ \hline
% 04-стектрейс & В упомянутый же парой минут ранее стектрейс кладётся максимальная информация о типе исключения, его сообщении, иерархии методов, вызовы которых привели к исключительной ситуации. Если не научиться читать стектрейс, если честно, можно расходиться по домам и не думать о серьёзном большом программировании. Итак стектрейс. Когда у нас случается исключение - мы видим, что случилось оно в потоке мэйн, и является объектом класса RuntimeException сообщение мы тоже предусмотрительно приложили. Первое что важно понять, что исключение - это объект класса. Далее читаем матрёшку - в каком методе создался этот объект, на какой строке, в каком классе. Далее смотрим кто вызвал этот метод, на какой строке, в каком классе. Это вообще самый простой стектрейс, который может быть. Бывают полотна по несколько десятков строк, клянусь, сам видел. Особенно важно научиться читать стектрейс разработчикам андроид, потому что именно такие стектрейсы будут вам прилетать в отчёт. У пользователя что то упало, он нажал на кнопку отправить отчёт, и вам в консоль разработчика прилетел стектрейс, который будет являться единственной доступной информацией о том, где вы или пользователь накосячили.\\ \hline
% лайвкод 04-простой-пример-исключения & Если мы не напишем никакого исключения, кстати, оно всё равно произойдёт. Это общее поведение исключения. Оно где-то случается, прекращает выполнение текущего метода, и начинает лететь по стеку вызовов вверх. Возможно даже долетит до дефолтного обработчика, как в этом примере.
% int[] arr = {1};
% System.out.println(arr[2])
% Некоторые исключения генерятся нами, некоторые самой джавой, они вполне стандартные, например выход за пределы массива, деление на ноль, и классический нуль-поинтер. \\ \hline
% лайвкод 04-объект-исключения & Посмотрим на исключения под немного другим углом. Создадим какой-нибудь учебный класс, psvm и создадим экземпляр класса исключения
% RuntimeException e = new RuntimeException();
% Если просто сейчас запустить программу, то ничего не произойдёт, нам нужно наше исключение, как бы это сказать, активировать, выкинуть, возбудить сгенерировать. Для этого есть ключевое слово
% throw e;
% Запускаем, видим. Компилятор ошибок не обнаружил и всё пропустил, а интерпретатор наткнулся на класс исключения, и написал нам в консоль следующее, в основном потоке программы возникло вот такое исключение в таком пакете в таком классе на такой строке.
% \\ \hline
% лайвкод 04-рантайм-выводы & Усложним создадим паблик стэтик воид методА, выкинем исключение в нём, и вызовем его из мэйна.
% теперь по вот этому стэктрейсу можем проследить что откуда вызвалось и как мы дошли до исключительной ситуации. Можем в нашем исключении даже написать наше кастомное сообщение и использовать все эти штуки в разработке. Можем унаследоваться от какого-то исключения и создать свой класс исключений, об этом чуть позже, в общем, всё зависит от поставленной задачи. Достаточно гибкая штука эти исключения. Ну и поскольку это рантаймэксепшн то обрабатывать его на этапе написания кода не обязательно, компилятор на него не ругается, всё круто. \\ \hline
% 04-иерархия-исключений & На самом деле на этом интересные особенности обработки исключений наследников Runtime, также называемых анчекд заканчивается далее будет гораздо интереснее рассматривать исключения обязательные для обработки, потому что статический анализатор кода не просто их выделяет, а обязывает их обрабатывать на этапе написания кода. И просто не скомпилирует проект если в коде есть необработанные так или иначе исключения также известные как чекд. Заменим Runtime исключение на обычное обязательное к обработке. ((удалить слово Runtime))\\ \hline
% 04-пробуй-лови & Давайте наше исключение ловить. Первое, и самое важное, что надо понять - это почему что-то упало, поэтому не пытайтесь что то ловить, пока не поймёте что именно произошло, от этого понимания будет зависеть способ ловли. Исключение ловится двухсекционным оператором try-catch, а именно, его первой секцией try. Это секция, в которой предполагается возникновение исключения, и предполагается, что мы можем его поймать. А в секции catch пишем имя класса исключения, которое мы ловим, и имя объекта, в который мы положим экземпляр нашего исключения. Секция catch ловит указанное исключение и всех его наследников. Это важно. Рекомендуется писать максимально узко направленные секции catch, потому что надо стараться досконально знать как работает ваша программа, и какие исключения она может выбрасывать. Ну и ещё потому что разные исключения могут по-разному обрабатываться, конечно-же. Секций catch может быть сколько угодно много. Как только мы обработали объект исключения, он уничтожается, дальше он не поднимается, и в следующие catch не попадает. Мы, конечно, можем его же насильно пульнуть выше, ключевым словом throw. \\ \hline
% 04-варианты ? & Так вот, когда какой-то наш метод выбрасывает исключение у нас есть два основных пути: вы обязаны либо вынести объявление этого исключения в сигнатуру метода, что будет говорить тем, кто его вызывает о том, что в методе может возникнуть исключение, либо мы это исключение должны непосредственно в методе обработать, иначе у вас ничего не скомпилируется. Примером одного из таких исключений служит ИО это сокращение от инпут-аутпут и генерируется, когда, вы не поверите, возникает ошибка ввода-вывода. То есть при выполнении программы что-то пошло не так и она, программа не может произвести ввод-вывод в штатном режиме. На деле много чего может пойти не так, операционка заглючила, флешку выдернули, устройство телепортировалось в микроволновку, и всё, случился ИОЭксепшн, не смогла программа прочитать или написать что то в потоке ввода-вывода. Соответственно, уже от этого ИОЭ возникают какие-то другие, вроде FileNotFoundException, которое мы тоже обязаны обработать. Например, мы хотим чтобы наша программа что то там прочитала из файла, а файла на нужном месте не оказалось, и метод чтения генерирует исключение. \\ \hline
% % +++ Комментатор_Ильнар. Мы вроде нигде про вынос в сигнатуру до этого не говорили, лучше до этих слов сказать что есть второй способ, а то читается так будто мы об этом уже сказали.
% 04-ответственность & В случае, если мы выносим объявление исключения в сигнатуру, вызывающий метод должен обработать это исключение точно таким-же образом - либо в вызове, либо вынести в сигнатуру. Исключением из этого правила является класс RuntimeException. Все наследники от него, включая его самого, обрабатывать не обязательно. Туда входит деление на ноль, индексаутофбаунд экзепшн например. то есть те ошибки, которые компилятор пропускает, а возникают они уже в среде исполнения. Обычно уже по названию понятно что случилось, ну и помимо говорящих названий, там ещё содержится много инфы, хотя-бы даже номер строки, вызвавшей исключительную ситуацию. Общее правило работы с исключениями одно - если исключение штатное - его надо сразу обработать, если нет - надо дождаться, пока программа упадёт. Повторю, все исключения надо обрабатывать, примите это как расплату за использование языка Java.\\ \hline
% лайвкод 04-обработка-вариант-1 & Вернёся к нашему учебному классу и Усложним ещё. в методеА вызовем методБ. а в методеБ выкинем то что нам обязательно надо обработать, например IOE. Вот тут то и начинается веселье. потому что IOE это не наследник рантайм эксепшена, и мы обязаны обрабатывать на этапе компиляции. Тут у нас есть две опции. многим уже известный try-catch, синтаксис его не совсем очевидный, так что тут надо просто сделать усилие и запомнить. пишем
% try { methodB() } catch (имя класса исключения которое хотим поймать и идентификатор экземпляра) { }.
% Если возникло исключение, попадём в кэтч, и тут можем делать что хотим, чтобы программа не упала. Конечно можно написать в кэтч общий класс вроде Throwable или Exception, вспомним про родительские классы, и тогда он поймает вообще все исключения которые могут быть, даже те, которые мы, возможно не ожидаем. Очень часто в процессе разработки нужно сделать, чтобы нам в процессе выполнения что-то конкретное об исключении выводилось на экран, для этого у экземпляра есть метод гетМессадж. Пишем
% sout(e.getMessage()).
% Ещё чаще бывает, что выполнение программы после выбрасывания исключения не имеет смысла и мы хотим чтобы программа упала. Вот тут очень интересный финт придумали. Мы выкидываем новое рантаймэкзепшн, передав в него экземпляр отловленного исключения используя довольно хитрый конструктор копирования. Во как
% catch throw new runtimeexception(e); \\ \hline
% лайвкод 04-обработка-вариант-2 & Второй вариант обработки исключений - мы в сигнатуре метода пишем
% throws IOE,
% и через запятую все остальные возможные исключения этого метода. Всё, у нас с ним проблем нет, но у метода который его вызовет - появились. И так далее наверх. Тут всё достаточно просто. Далее пробуем описать какое-то исключение, которое мы обязаны будем ловить. Предлагаю переименовать наш учебный класс и его методы в некоторую имитацию потока ввода-вывода.
% Класс ТестСтрим
% методА = конструктор
% методБ = инт читать
% Внутри методаБ давайте создадим какой-нибудь FileInputStream который может генерить FileNotFoundException который на самом деле является наследником IOE, который наследуется от Exception. Никаких рантайм, значит обработать мы его обязаны. Два варианта у нас есть, либо мы его укутаем в try-catch, либо вот не можете вы написать обработчик, потому что не знаете как должна обрабатываться данная исключительная ситуация, и обработать её должна сторона, которая вызывает метод чтения, в таком случае пишем, что метод может генерить исключения. Всё, вы теперь свободны от обработки этого исключения в методе чтения. Но теперь подчёркивается метод мейн... и здесь мы встаём перед той-же дилеммой. и так далее по стэку вызовов любой глубины. \\ \hline
% вовочка перед печкой «и так сойдёт» & Важный момент. Задачи бывают разные. Исключения - это инструмент, который нетривиально работает. Важно при написании кода понять, возникающая исключительная ситуация - штатная, или нештатная. В большинстве случаев - ситуации нештатные, поэтому надо уронить приложение и разбираться с тем, что произошло. Допустим для вашего приложения вот стопроцентно какой-то файл должен быть, без него дальше нет смысла продолжать. Что делать, если его нет? Явно не пытаться в него что то писать, правда? Самое плохое, что можно сделать - ничего не делать. Это самое страшное, когда программа повела себя как-то не так, а мы об этом даже не узнали. Допустим мы хотим прочитать файл, вывести в консоль, но мы глотаем исключение, выведя стектрейс куда-то-там какому-то разработчику и наши супер-важные действия не выполнились. Надо ронять. Как ронять? да throw new RuntimeException(e). Крайне редко случаются ситуации, когда исключение надо проглотить. \\ \hline
% лайвкод 04-файналли & Давайте обрабатывать дальше. Все помнят, что потоки надо закрывать? Даже если не знали, теперь знаете. Вот, допустим, у нас в нашем модном потоке открылся файл, что то из него прочиталось, потом метод упал с исключением, а файл остался незакрытым, ресурсы заняты. Давайте даже допишем свой класс TestStream пусть его конструктор выбрасывает IOE, метод read выбрасывает IOE и будет метод close, везде будем логировать успешность в read пока оставляем исключение throw new IOE("reading error") в close "closed". Штатно возвращаем из read единичку и логируем, что всё прочитали в мейне. Как всё будет происходить штатно?
% TestStream stream = new TestStream();
% int a = stream.read()
% stream.close()
% Далее представим что в методе read что то пошло не так, выбрасываем исключение, и что видим в консоли? создали поток, исключение, конец программы. Что же делать? а делать секцию finally. Секция finally будет выполнена в любом случае, будет исключение, не будет исключения, не важно. Но тут тоже большое спасибо разработчикам джавы, мы не видим наш поток, то есть его надо вынести наружу, а ещё он оказывается не инициализирован, значит надо написать что то типа TestStream stream = null. Теперь всё должно отработать. \\ \hline
% лайвкод 04-проблема & Теперь немного неприятностей. Написали мы блок finally, вроде даже избавились от проблемы с закрытием потока. А как быть, если исключение возникло при создании этого потока? Тогда получается, у нас метод закрытия будет пытаться выполниться от ссылки на null. Нехорошо, знаете-ли, получается. Давайте всё сломаем, прям в конструкторе нашего потока выкинем IOE. Получили NPE в блоке finally. Очевидное решение - ставим в секции finally условие, и если поток не равен нулю, закрываем. Вроде клёво. Меняем тактику. Конструктор отрабатывает нормально. Метод чтения всё ещё генерирует исключение, но бац и в методе закрытия что-то пошло не так, и вылетело исключение. Ну вот так не повезло в жизни. Что делаем? Оборачиваем в try-catch. Вроде снова всё классно. Но и тут мы можем наткнуться на неприятность. Допустим, что нам надо в любом случае ронять приложение (в кэтч допишем throw new Runtime...). Тогда если у нас try поймал исключение, и выкинул его, потом finally всё равно выполнится, и второе исключение затрёт первое, мы его не увидим. Ну а поскольку первое для нас важнее, то второе - максимум что мы можем сделать - это залогировать исключение в консольку. Так дела обстояли в седьмой джаве. \\ \hline
% лайвкод 04-с-ресурсами & Что предлагает нам восьмая джава? try-с-ресурсами. Поток - это ресурс, абстрактное понятие. Как с этим работать? Сейчас будет небольшое забегание вперёд, пока что предлагаю просто запомнить магию. Выражаясь строго формально, мы должны реализовать интерфейс Closeable. А что это за интерфейс? (Ctrl+click) там содержится всего один метод close(), который умеет бросать IOE. Напишем везде пока что штатное поведение в нашем тестовом потоке. Залогируем. Далее синтаксис try-с-ресурсами. Все потоки начиная с восьмой джавы реализуют интерфейс Closeable. Стираем все ужасы, которые мы написали, пишем
% try(TestStream stream = new TestStream())
% int a = stream.read();
% catch (IOException e)
% new RuntimeException(e)
% И всё, мы поток не закрываем. За это у нас ответит сама джава. Запустим и проверим. Никаких close() и finally, всё хорошо. Самое классное - если мы ломаем метод read() то трай с ресурсами всё равно наш поток корректно закроет. Иногда вы можете видеть вывод в консоль и стектрейс вразнобой, ничего страшного, просто исключения вылетают в поток error а вывод в консоль в стандартный вывод. Ну и у них иногда случаются асинхронности. А теперь вообще самый смак - ломаем метод закрытия, и джава очень правильно поступит, она выкатит наверх основное исключение, но и выведет "подавленное" исключение, вторичное в стектрейс. По-человечески, красиво, информативно, глаз радуется. Рекомендуется по возможности использовать вот такую конструкцию. Но научиться пользоваться надо и тем и тем, естественно. \\ \hline
% % Комментатор_Ильнар. Смотри, многие тут потеряются походу этой лекции про вложенные классы и исключения. Понятно что про ресурс надо объяснить почему без него костылить многие вещи сложно, но многие в этом могут запутаться. Добавь пожалуйста резюме на пальцах после таких блоков. Мол, если уже успели запутаться и потеряться, то вот вам простая инструкция - исключения либо прокидываем, либо обрабатываем. Прокидываем так, обрабатываем в try catch finaly. Есть для обработки прекрасная штука try с ресурсами. для чего все это нужно - можно переслушать то что я рассказал после того как поиграете со всем этим на семинаре. Переслушивать можно медленно и конспектируя несколько раз пока не дойдет, не стесняйтесь это делать. Такое же резюме можно по вложенным классам сделать, чтобы их немного успокоить
% 03-наследование & Последнее на сегодня про исключения это наследования и Полиморфизм исключения тема не очень большая и в целом не сложная потому что вы уже знаете что такое класса объекты как классы могут наследоваться и что такое Полиморфизм. Особенно застрять внимание на объектно-ориентированном программирования исключениях скорее всего не нужно потому что было неоднократно сказано что исключение это тоже классы и есть какие-то наследники исключений генерируются и выбрасываю объекты исключений единственное что важно упомянуть это то что под система исключений работает немного не тривиально впрочем это вы могли заметить и сами но мы можем создавать собственные исключения с собственными смыслами и сообщениями и точно также их выбрасывать вместо стандартных наследоваться мы можем от любых исключений единственное что важно это то что не рекомендуется наследоваться от классов throwable и error когда описываете исключение механика checked и unchecked исключений сохраняется при наследование поэтому создав наследник RuntimeException вы получаете не проверяемые на этапе написания кода исключение \\ \hline
% На этом уроке & На этой лекции в дополнение к предыдущей, разобрали такие понятия как внутренние и вложенные классы, было непросто, но мы, кажется, справились; процессы создания, использования и расширения перечислений. Детально разобрали уже знакомое вам понятие исключений и их тесную связь с многопоточностью в джава. Всё время смотрели на исключения с точки зрения ООП, обработали немного исключений, а также раз и навсегда разделили понятия штатных и нештатных ситуаций. \\ \hline
\subsection*{Практическое задание}
\begin{enumerate}
\item Написать класс кота так, чтобы каждому объекту кота присваивался личный порядковый целочисленный номер.
\item напишите два наследника класса Exception: ошибка преобразования строки и ошибка преобразования столбца
\item разработайте исключения-наследники так, чтобы они информировали пользователя в формате ожидание/реальность
\item для проверки напишите программу, преобразующую квадратный массив целых чисел 5х5 в сумму чисел в этом массиве, при этом, программа должна выбросить исключение, если строк или столбцов в исходном массиве окажется не 5.
\end{enumerate}
\newpage
\printnomenclature[40mm]
\end{document}
% enum Color{
% RED("#FF0000"), BLUE("#0000FF"), GREEN("#00FF00");
% private String code;
% Color(String code){
% this.code = code;
% }
% public String getCode(){ return code;}
% }
%public class Main{
% public static void main(String[] args) {
% System.out.println(Color.RED.getCode());
% System.out.println(Color.GREEN.getCode());
% }
%}
% package ru.gb.jcore;
% public class Orange {
% public void squeezeJuice(){
% System.out.println("Squeeze juice ...");
% }
% class Juice{
% public void flow(){
% System.out.println("Juice dripped ...");
% }
% }
% }
% package ru.gb.jcore;
% public class Main {
% public static void main(String[] args) {
% Orange orange = new Orange();
% Orange.Juice juice = orange.new Juice();
% orange.squeezeJuice();
% juice.flow();
% }
% }
%///////////////////////////////
% public class Orange {
% private Juice juice;
% public Orange(){
% this.juice = new Juice();
% }
% public void squeezeJuice(){
% System.out.println("Squeeze juice ...");
% juice.flow();
% }
% private class Juice{
% public void flow(){
% System.out.println("Juice dripped ...");
% }
% }
% }
% public class Main {
% public static void main(String[] args) {
% Orange orange = new Orange();
% orange.squeezeJuice();
% }
% }

View File

@ -26,9 +26,9 @@
showgrid="true"
showborder="false"
borderlayer="false"
inkscape:zoom="8.6634554"
inkscape:cx="594.39332"
inkscape:cy="469.78945"
inkscape:zoom="1.9531432"
inkscape:cx="431.86797"
inkscape:cy="488.95543"
inkscape:window-width="1511"
inkscape:window-height="832"
inkscape:window-x="0"
@ -111,12 +111,12 @@
id="layer1">
<text
xml:space="preserve"
style="font-size:4.93888889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="60.956562"
y="96.191261"
id="text790"><tspan
sodipodi:role="line"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-opacity:1;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-opacity:1"
x="60.956562"
y="96.191261"
id="tspan11908">java class file</tspan></text>
@ -133,155 +133,155 @@
y="124.11515" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="111.84619"
y="96.395851"
id="text848"><tspan
sodipodi:role="line"
id="tspan846"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
x="111.84619"
y="96.395851">class loader</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="66"
y="124"
id="text2304"><tspan
sodipodi:role="line"
id="tspan2302"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265;font-size:4.23333333px"
x="66"
y="124">method area</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="102.36334"
y="123.94704"
id="text3034"><tspan
sodipodi:role="line"
id="tspan3032"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265;font-size:4.23333333px"
x="102.36334"
y="123.94704">heap</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="126.9079"
y="123.80221"
id="text3038"><tspan
sodipodi:role="line"
id="tspan3036"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265;font-size:4.23333333px"
x="126.9079"
y="123.80221">stack</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="152"
y="124"
id="text3768"><tspan
sodipodi:role="line"
id="tspan3766"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265;font-size:4.23333333px"
x="152"
y="124">java threads</tspan></text>
<text
xml:space="preserve"
style="font-size:4.93888889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
style="font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
x="122.48949"
y="133.47887"
id="text4498"><tspan
sodipodi:role="line"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="122.48949"
y="133.47887"
id="tspan4500">program counter registers</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="66"
y="134"
id="text5230"><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265;font-size:4.23333333px"
x="66"
y="134"
id="tspan5232">native internal threads</tspan></text>
<text
xml:space="preserve"
style="font-size:4.93888889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
style="font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
x="73.237595"
y="155.814"
id="text5962"><tspan
sodipodi:role="line"
id="tspan5960"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="73.237595"
y="155.814">execution engine</tspan></text>
<text
xml:space="preserve"
style="font-size:4.93888889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
style="font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
x="57.221085"
y="163.8349"
id="text6329"><tspan
sodipodi:role="line"
id="tspan6327"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="57.221085"
y="163.8349">JIT compiler</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1"
x="91"
y="164"
id="text7422"><tspan
sodipodi:role="line"
id="tspan7420"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';stroke-width:0.265;font-size:4.23333333px"
x="91"
y="164">garbage collector</tspan></text>
<text
xml:space="preserve"
style="font-size:4.93888889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
style="font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
x="141.01183"
y="157.82979"
id="text8152"><tspan
sodipodi:role="line"
id="tspan8150"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="141.01183"
y="157.82979">native method</tspan><tspan
sodipodi:role="line"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="141.01183"
y="164.00342"
id="tspan8154">interface</tspan></text>
<text
xml:space="preserve"
style="font-size:4.93888889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
style="font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
x="181.05193"
y="157.77907"
id="text8884"><tspan
sodipodi:role="line"
id="tspan8882"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="181.05193"
y="157.77907">native method</tspan><tspan
sodipodi:role="line"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="181.05193"
y="163.9527"
id="tspan8886">library</tspan></text>
<text
xml:space="preserve"
style="font-size:4.93888889px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
style="font-size:4.23333333px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-opacity:1;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
x="103.22704"
y="115.05011"
id="text10342"><tspan
sodipodi:role="line"
id="tspan10340"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.93888889px"
style="stroke-width:0.265;-inkscape-font-specification:'IBM Plex Sans';font-family:'IBM Plex Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:4.23333333px"
x="103.22704"
y="115.05011">runtime data area</tspan></text>
<text
@ -368,8 +368,8 @@
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.264999;stroke-opacity:1"
id="rect13444"
width="49.896049"
height="4.9799647"
width="50.938873"
height="5.0722198"
x="65.061127"
y="129.92778" />
<rect

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

595
pics/jc-04-throwable.svg Normal file
View File

@ -0,0 +1,595 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg2322"
inkscape:version="1.2.1 (9c6d41e4, 2022-07-14)"
sodipodi:docname="jc-04-throwable.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview2324"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
inkscape:zoom="2.0877419"
inkscape:cx="305.59334"
inkscape:cy="296.2531"
inkscape:window-width="1529"
inkscape:window-height="935"
inkscape:window-x="151"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid4258" />
</sodipodi:namedview>
<defs
id="defs2319" />
<g
inkscape:label="Слой 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="84.666664"
y="15.875"
id="text4625"><tspan
sodipodi:role="line"
id="tspan4623"
style="stroke-width:0.265"
x="84.666664"
y="15.875">Throwable</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="11.906249"
y="35.71875"
id="text4629"><tspan
sodipodi:role="line"
id="tspan4627"
style="stroke-width:0.265"
x="11.906249"
y="35.71875">Error</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="3.9687486"
y="46.302082"
id="text4633"><tspan
sodipodi:role="line"
id="tspan4631"
style="stroke-width:0.265"
x="3.9687486"
y="46.302082">подклассы</tspan><tspan
sodipodi:role="line"
style="stroke-width:0.265"
x="3.9687486"
y="52.475708"
id="tspan4635">Error</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="105.83335"
y="25.135418"
id="text4639"><tspan
sodipodi:role="line"
id="tspan4637"
style="stroke-width:0.265"
x="105.83335"
y="25.135418">Exception</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="63.5"
y="105.83334"
id="text5369"><tspan
sodipodi:role="line"
id="tspan5367"
style="stroke-width:0.265"
x="63.5"
y="105.83334">другие</tspan><tspan
sodipodi:role="line"
style="stroke-width:0.265"
x="63.5"
y="112.00696"
id="tspan5371">подклассы</tspan><tspan
sodipodi:role="line"
style="stroke-width:0.265"
x="63.5"
y="118.18058"
id="tspan5373">Exception</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="59.53125"
y="31.75"
id="text5377"><tspan
sodipodi:role="line"
id="tspan5375"
style="stroke-width:0.265"
x="59.53125"
y="31.75">IOException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="43.65625"
y="42.333332"
id="text5381"><tspan
sodipodi:role="line"
id="tspan5379"
style="stroke-width:0.265"
x="43.65625"
y="42.333332">ClassNotFoundException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="43.65625"
y="52.916668"
id="text5385"><tspan
sodipodi:role="line"
id="tspan5383"
style="stroke-width:0.265"
x="43.65625"
y="52.916668">CloneNotSupportedException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="43.65625"
y="63.5"
id="text5389"><tspan
sodipodi:role="line"
id="tspan5387"
style="stroke-width:0.265"
x="43.65625"
y="63.5">EOFException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="43.65625"
y="74.083336"
id="text5393"><tspan
sodipodi:role="line"
id="tspan5391"
style="stroke-width:0.265"
x="43.65625"
y="74.083336">FileNotFoundException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="43.65625"
y="84.666664"
id="text5397"><tspan
sodipodi:role="line"
id="tspan5395"
style="stroke-width:0.265"
x="43.65625"
y="84.666664">MalformedURLException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="43.65625"
y="95.25"
id="text5401"><tspan
sodipodi:role="line"
id="tspan5399"
style="stroke-width:0.265"
x="43.65625"
y="95.25">UnknownHostException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="148.16667"
y="31.75"
id="text5405"><tspan
sodipodi:role="line"
id="tspan5403"
style="stroke-width:0.265"
x="148.16667"
y="31.75">RuntimeException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="142.87498"
y="42.333332"
id="text5409"><tspan
sodipodi:role="line"
id="tspan5407"
style="stroke-width:0.265"
x="142.87498"
y="42.333332">NullPointerException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="126.99999"
y="52.916668"
id="text5413"><tspan
sodipodi:role="line"
id="tspan5411"
style="stroke-width:0.265"
x="126.99999"
y="52.916668">IndexOutOfBoundsException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="128.32292"
y="63.5"
id="text5417"><tspan
sodipodi:role="line"
id="tspan5415"
style="stroke-width:0.265"
x="128.32292"
y="63.5">ArrayIndexOutOfBoundException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="132.29166"
y="74.083336"
id="text5421"><tspan
sodipodi:role="line"
id="tspan5419"
style="stroke-width:0.265"
x="132.29166"
y="74.083336">IllegalArgumentException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="145.52081"
y="84.666664"
id="text5425"><tspan
sodipodi:role="line"
id="tspan5423"
style="stroke-width:0.265"
x="145.52081"
y="84.666664">NumberFormatException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="142.87498"
y="105.83334"
id="text5429"><tspan
sodipodi:role="line"
id="tspan5427"
style="stroke-width:0.265"
x="142.87498"
y="105.83334">ClassCastException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="142.87498"
y="95.25"
id="text5433"><tspan
sodipodi:role="line"
id="tspan5431"
style="stroke-width:0.265"
x="142.87498"
y="95.25">ArithmeticException</tspan></text>
<text
xml:space="preserve"
style="font-size:4.9389px;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans';fill:#000000;stroke-width:0.264999;stroke-linecap:square"
x="157.42709"
y="116.41668"
id="text5437"><tspan
sodipodi:role="line"
id="tspan5435"
style="stroke-width:0.265"
x="157.42709"
y="116.41668">другие </tspan><tspan
sodipodi:role="line"
style="stroke-width:0.265"
x="157.42709"
y="122.5903"
id="tspan5439">подклассы</tspan><tspan
sodipodi:role="line"
style="stroke-width:0.265"
x="157.42709"
y="128.76393"
id="tspan5441">RuntimeException</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5495"
width="17.197916"
height="6.6145835"
x="9.260417"
y="30.427084" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5497"
width="29.104166"
height="11.90625"
x="2.6458328"
y="42.333332" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5499"
width="26.458332"
height="6.614583"
x="83.34375"
y="10.583333" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5501"
width="25.135416"
height="6.614583"
x="104.51041"
y="19.84375" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5503"
width="30.427082"
height="6.614583"
x="58.208332"
y="26.458332" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5505"
width="59.53125"
height="6.614583"
x="42.333332"
y="37.041668" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5507"
width="70.114586"
height="6.614583"
x="42.333332"
y="47.625" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5509"
width="34.395832"
height="6.614583"
x="42.333332"
y="58.208332" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5511"
width="55.5625"
height="6.614583"
x="42.333332"
y="68.791664" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5513"
width="59.53125"
height="6.614583"
x="42.333332"
y="79.375" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5515"
width="58.208332"
height="6.614583"
x="42.333332"
y="89.958336" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5517"
width="30.427084"
height="18.520838"
x="62.177082"
y="101.86458" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5519"
width="44.979168"
height="6.614583"
x="146.84375"
y="26.458332" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5521"
width="51.59375"
height="6.614583"
x="141.55208"
y="37.041668" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5523"
width="70.114586"
height="6.614583"
x="125.67709"
y="47.625" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5525"
width="78.052086"
height="6.614583"
x="126.99999"
y="58.208332" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5527"
width="63.5"
height="6.614583"
x="129.64583"
y="68.791664" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5529"
width="59.53125"
height="6.614583"
x="144.19792"
y="79.375" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5531"
width="48.947918"
height="6.614583"
x="141.55208"
y="89.958336" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5533"
width="47.625"
height="6.614583"
x="141.55208"
y="100.54166" />
<rect
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
id="rect5535"
width="44.979168"
height="18.520834"
x="156.10417"
y="112.44791" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 17.197917,37.041666 v 5.291667"
id="path5593" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="M 58.208334,29.104167 H 37.041667 v 63.5 h 5.291667"
id="path5609" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 37.041667,82.020833 h 5.291667"
id="path5611" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 37.041667,71.4375 h 5.291667"
id="path5613" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 37.041667,60.854167 h 5.291667"
id="path5615" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 37.041667,50.270834 h 5.291667"
id="path5617" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 37.041667,39.687501 h 5.291667"
id="path5619" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="M 83.343749,13.229167 H 17.197916 v 17.197916"
id="path5621" />
<circle
id="path5623"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="37.041668"
cy="39.6875"
r="0.39749998" />
<circle
id="path5625"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="37.041668"
cy="50.270832"
r="0.39749998" />
<circle
id="path5627"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="37.041668"
cy="60.854164"
r="0.39749998" />
<circle
id="path5629"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="37.041668"
cy="71.4375"
r="0.39749998" />
<circle
id="path5631"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="37.041668"
cy="82.020836"
r="0.39749998" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 109.80208,13.229167 h 7.9375 v 6.614583"
id="path5633" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="M 115.09375,26.458333 V 109.80208 H 92.604166"
id="path5635" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="M 88.635416,30.427083 H 146.84375"
id="path5637" />
<circle
id="path5639"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="115.09375"
cy="30.427082"
r="0.39749998" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 191.82291,30.427083 h 15.875 V 119.0625 h -6.61458"
id="path5641" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 207.69791,39.6875 -14.55208,0"
id="path5643"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 207.69791,50.270833 -11.90624,0"
id="path5645"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="M 207.69791,71.437499 H 193.14583"
id="path5647" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="M 207.69791,92.604166 H 190.5"
id="path5649" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="M 207.69791,103.1875 H 189.17708"
id="path5651" />
<circle
id="path5653"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="207.69791"
cy="103.1875"
r="0.39749998" />
<circle
id="path5655"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="207.69791"
cy="92.604164"
r="0.39749998" />
<circle
id="path5657"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="207.69791"
cy="71.4375"
r="0.39749998" />
<circle
id="path5659"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="207.69791"
cy="50.270832"
r="0.39749998" />
<circle
id="path5661"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="207.69791"
cy="39.6875"
r="0.39749998" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 125.67708,50.270833 h -3.96875 l 0,10.583333 H 127"
id="path5663"
sodipodi:nodetypes="cccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:square;stroke-opacity:1"
d="m 129.64583,71.437499 h -5.29166 v 10.583333 h 19.84374"
id="path5665" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Binary file not shown.

View File

@ -5,10 +5,11 @@
\section{Семинар: компиляция и интерпретация кода}
\subsection{Инструментарий}
\begin{itemize}
\item Презентация для преподавателя, ведущего семинар;
\item \href{https://docs.google.com/presentation/d/1LPMWfXpjkJDOMR4lv7y5Ss6_ABSocZtoc7nVEVs6FQo}{Презентация для преподавателя}, ведущего семинар;
\item \href{https://drive.google.com/file/d/1LWyE8aEy4-1gsognqhXIXwDcoLviVge4/view}{Фон} GeekBrains для проведения семинара в Zoom;
\item \href{https://jupyter.org/install}{Jupyter Notebook} для практики и примеров используется Jupyter notebook (потребуется установить \href{https://www.python.org/downloads/}{Python} и ядро \href{https://github.com/SpencerPark/IJava}{IJava}) и любой терминал операционной системы (bash, zsh, cmd);
\item JDK любая 11 версии и выше;
\item \href{https://docs.docker.com/get-docker}{Docker}, \href{https://www.gnu.org/software/automake/}{make}.
\end{itemize}
\subsection{Цели семинара}
@ -272,7 +273,7 @@ java -classpath ./out ru.gb.jcore.Main
System.out.print("Your number is " + a);
\end{lstlisting}
\item [$*_1$] сохранить форматирующую строку в ячейке с переменной
\item [$*_2$] сохранить форматирующую строку в ячейке с переменной
\begin{figure}[H]
\centering
\includegraphics[width=120mm]{sem-01-t2-2.png}
@ -338,9 +339,9 @@ javadoc -d doc_bg -sourcepath . -cp ./out ru.bg
\item [5-25 мин] Решить все задания (в том числе «со звёздочкой»), если они не были решены на семинаре, без ограничений по времени;
Все варианты решения приведены в тексте семинара выше
\item [10-15 мин] Создать докер образ для формирования полной документации по проекту
\item [10-15 мин] Создать docker-контейнер для формирования полной документации по проекту
\lstinputlisting[style=CCodeStyle,caption={docker-compose-class.yml}]{src/s01-h04-docker-compose-docs.yml}
\lstinputlisting[style=CCodeStyle,caption={docker-compose-class.yml}]{src/s01-hw2-docker-compose-docs.yml}
\end{enumerate}
\end{itemize}

View File

@ -2,6 +2,7 @@
\usepackage{spreadtab}
\begin{document}
\setcounter{section}{1}
\section{Семинар: данные и функции}
\subsection{Инструментарий}
\begin{itemize}
@ -79,7 +80,15 @@
\end{itemize}
\item \textbf{Вопросы и ответы:}
\begin{enumerate}
\item
\item Магическое число -- это: (1)
\begin{enumerate}
\item числовая константа без пояснений;
\item число, помогающее в вычислениях;
\item числовая константа, присваиваемая при объявлении переменной.
\end{enumerate}
\item Какое значение будет содержаться в переменной a после выполнения строки \code{int а = 10.0f/3.0f;} (3)
\item Сколько будет создано одномерных массивов при инициализации массива 3х3x3? (13)
\item \code{2 + 2 * 2 == 2 << 2 >> 1}? (false? 6 != 4)
\end{enumerate}
\end{itemize}
@ -381,8 +390,23 @@ void pigeon(int[] arr) {
\end{itemize}
\item \textbf{Задания}
\begin{enumerate}
\item Решить все задания (в том числе «со звёздочкой»), если они не были решены на семинаре, без ограничений по времени;
\item
\item [5-25 мин] Решить все задания (в том числе «со звёздочкой»), если они не были решены на семинаре, без ограничений по времени;
Все варианты решения приведены в тексте семинара выше
\item [5-10 мин] Написать метод, возвращающий количество чётных элементов массива.
\begin{itemize}
\item [] \code{countEvens([2, 1, 2, 3, 4])} $\to$ \code{3}
\item [] \code{countEvens([2, 2, 0])} $\to$ \code{3}
\item [] \code{countEvens([1, 3, 5])} $\to$ \code{0}
\end{itemize}
\lstinputlisting[language=Java,style=JCodeStyle,caption={CountEvens.java}]{src/s02-hw2-count.java}
\item [10 мин] Написать функцию, возвращающую разницу между самым большим и самым маленьким элементами переданного не пустого массива.
\lstinputlisting[language=Java,style=JCodeStyle,caption={Spread.java}]{src/s02-hw2-spread.java}
\item [10 мин] Написать функцию, возвращающую истину, если в переданном массиве есть два соседних элемента, с нулевым значением.
\lstinputlisting[language=Java,style=JCodeStyle,caption={Zero2.java}]{src/s02-hw2-zeros.java}
\end{enumerate}
\end{itemize}

View File

@ -0,0 +1,9 @@
int countEvens(int[] arr) {
int counter = 0;
for (int i = 0; i < arr.length; ++i) {
if (arr[i] % 2 == 0) {
counter++;
}
}
return counter;
}

View File

@ -0,0 +1,9 @@
int spread(int[] arr) {
int min = arr[0];
int max = arr[0];
for (int i = 1; i < arr.length; ++i) {
if (arr[i] < min) min = arr[i];
if (arr[i] > max) max = arr[i];
}
return max - min;
}

View File

@ -0,0 +1,7 @@
boolean zero2(int[] arr) {
for (int i = 0; i < arr.length - 1; ++i) {
if (arr[i] == 0 && arr[i + 1] == 0)
return true;
}
return false;
}