02a started

This commit is contained in:
Ivan I. Ovchinnikov 2022-09-22 01:22:58 +03:00
parent 28d196ebe4
commit c918909f94
7 changed files with 505 additions and 70 deletions

Binary file not shown.

View File

@ -27,8 +27,6 @@
\subfile{jtd6-11a}
\section{Специализация: ООП}
Инкапсуляция: Классы и объекты (внутренние классы, вложенные классы, static, private/public, final, интерфейс взаимодействия с объектом), перечисления (создание, конструкторы перечислений, объекты перечислений, дополнительные свойства); Наследование: extends, Object (глобальное наследование), protected, преобразование типов, final; Полиморфизм: override, abstract, final;
%\subfile{scenarios/jc-4}
\section{Специализация: Тонкости работы}
Файловая система и представление данных; Пакеты \code{java.io}, \code{java.nio}, \code{String}, \code{StringBuilder}, string pool, ?JSON/XML?

View File

@ -16,27 +16,38 @@
Будет рассмотрен базовый функционал языка, то есть основная встроенная функциональность, такая как математические операторы, условия, циклы, бинарные операторы. Далее способы хранения и представления данных в Java, и в конце способы манипуляции данными, то есть функции (в терминах языка называющиеся методами).
\subsection{Данные}
\subsubsection{Типы, преобразование типов}
%константы и переменные (примитивные, ссылочные), бинарное представление, массивы (ссылочная природа массивов, индексация, манипуляция данными)
\subsubsection{Понятие типов}
Хранение данных в Java осуществляется привычным для программиста образом: в переменных и константах.
Хранение данных в Java осуществляется привычным для программиста образом: в переменных и константах. Языки программирования бывают типизированными и нетипизированными (бестиповыми).
Относительно типизации языки программирования бывают типизированными и нетипизированными (бестиповыми). Нетипизированные языки не представляют большого интереса в современном программировании.
Отсутствие типизации в основном присуще чрезвычайно старым и низкоуровневым языкам программирования, например, Forth и некоторым ассемблерам. Все данные в таких языках считаются цепочками бит произвольной длины и не делятся на типы. Работа с ними часто труднее, при этом часто безтиповые языки работают быстрее типизированных, но описывать с их помощью большие проекты со сложными взаимосвязями довольно утомительно.
Отсутствие типизации в основном присуще старым и низкоуровневым языкам программирования, например, Forth, некоторые ассемблеры. Все данные в таких языках считаются цепочками бит произвольной длины и, как следует из названия, не делятся на типы. Работа с ними часто труднее, и при чтении кода не всегда ясно, о каком типе переменной идет речь. При этом часто безтиповые языки работают быстрее типизированных, но описывать с их помощью большие проекты со сложными взаимосвязями довольно утомительно.
\begin{frm}
\info Java является языком со \textbf{строгой} (также можно встретить термин «\textbf{сильной}») \textbf{явной} \textbf{статической} типизацией.
\end{frm}
Что это значит?
\begin{itemize}
\item Статическая - у каждой переменной должен быть тип и мы этот тип поменять не можем. Этому свойству противопоставляется динамическая типизация;
\item Явная - при создании переменной мы должны ей обязательно присвоить какой-то тип, явно написав это в коде. Бывают языки с неявной типизацией, например, Python;
\item Статическая - у каждой переменной должен быть тип, и этот тип изменить нельзя. Этому свойству противопоставляется динамическая типизация;
\item Явная - при создании переменной ей обязательно необходимо присвоить какой-то тип, явно написав это в коде. В более поздних версиях языка (с 9й) стало возможным инициализировать переменные типа \code{var}, обозначающий нужный тип тогда, когда его возможно однозначно вывести из значения справа. Бывают языки с неявной типизацией, например, Python;
\item Строгая(сильная) - невозможно смешивать разнотипные данные. С другой стороны, существует JavaScript, в котором запись \code{2 + true} выдаст результат \code{3}.
\end{itemize}
Все данные в Java делятся на две основные категории: примитивные и ссылочные.
\subsubsection{Антипаттерн «магические числа»}
Почти во всех примерах, которые используются для обучения, можно увидеть так называемый антипаттерн - плохой стиль для написания кода. Числа, которые находятся справа от оператора присваивания используются в коде без пояснений. Такой антипаттерн называется «магическое число». Магическое, потому что непонятно, что это за число, почему это число именно такое и что будет, если это число изменить.
Данные: типы, преобразование типов, константы и переменные (примитивные, ссылочные), бинарное представление, массивы (ссылочная природа массивов, индексация, манипуляция данными);
Так лучше не делать. Заранее нужно сказать, что рекомендуется помещать все числа в коде в именованные константы, которые хранятся в начале файла. Плюсом такого подхода является возможность легко корректировать значения переменных в достаточно больших проектах.
\begin{figure}[H]
Например, в вашем коде несколько тысяч строк, а какое-то число, скажем, возраст совершеннолетия, число 18, использовалось несколько десятков раз. При использовании приложения в стране, где совершеннолетием считается $21$ год вы должны будете перечитывать весь код в поисках магических «18» и исправить их на «21». В этом вопросе будет также важно не запутаться, действительно ли это $18$, которые означают совершеннолетие, а не количество карманов в жилетке Анатолия Вассермана\footnote{мы то знаем, что их 26}.
В случае с константой изменить число нужно в одном месте.
\subsection{Примитивные типы данных}
Все данные в Java делятся на две основные категории: примитивные и ссылочные. Таблица \hrf{tab:types} демонстрирует все восемь примитивных типов языка и их размерности. Чтобы отправить на хранение какие-то данные используется оператор присваивания. Присваивание в программировании - это не тоже самое, что математическое равенство, демонстрирующее тождественность, а полноценная операция.
Все присваивания всегда происходят справа налево, то есть сначала вычисляется правая часть, а потом результат вычислений присваивается левой. Исключений нет, именно поэтому в левой части не может быть никаких вычислений.
\begin{table}
\centering
\begin{tabular}{|p{17mm}|p{80mm}|p{55mm}|}
\hline
@ -61,24 +72,92 @@
\end{tabular}
\caption{Основные типы данных в языке Java}
\label{tab:types}
\end{figure}
\end{table}
Базовые функции языка: математические операторы, условия, циклы, бинарные операторы;
Шесть из восьми типов имеет диапазон значений, а значит основное их отличие в объёме занимаемой памяти. У \code{double} и \code{float} тоже есть диапазоны, но они заключаются в точности представления дробной части. Диапазоны означают, что если попытаться положить в переменную меньшего типа большее значение, произойдёт «переполнение переменной».
Функции: параметры, возвращаемые значения, перегрузка функций;
\subsubsection{Переполнение целочисленных переменных}
Чем именно чревато переполнение переменной легче показать на примере (по ссылке - \href{https://habr.com/ru/company/pvs-studio/blog/306748/}{расследование} крушения ракеты из-за переполнения переменной)
\begin{frm} \excl Переполнение переменных не распознаётся компилятором. \end{frm}
Если создать переменную типа byte, диапазон которого от $[-128, +127]$, и присвоить этой переменной значение $200$ произойдёт переполнение, как если попытаться влить пакет молока в напёрсток.
\begin{frm} \info Переполнение переменной - это ситуация, в которой происходит попытка положить большее значение в переменную меньшего типа. \end{frm}
Важным вопросом при переполнении остаётся следующий: какое в переполненной переменной останется значение? Максимальное, $127$? $200 - 127 = 73$? Какой-то мусор? Каждый язык, а зачастую и разные компиляторы одного языка ведут себя в этом вопросе по разному.
\begin{frm}
\begin{center}
\excl В современном мире гигагерцев и терабайтов почти никто не пользуется маленькими типами, но именно из-за этого ошибки переполнения переменных становятся опаснее испанской инквизиции.
\includegraphics[width=5cm]{jc-02-spanish.jpg}
\end{center}
\end{frm}
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item длдлдл
\end{enumerate}
\subsubsection{Антипаттерн "магические числа"}
В прошлом примере мы использовали антипаттерн - плохой стиль для написания кода. Число 18 используется в коде коде без пояснений. Такой антипаттерн называется "магическое число". Рекомендуется помещать числа в константы, которые храняться в начале файла.
ADULT = 18
age = float(input('Ваш возраст: '))
how\_old = age - ADULT
print(how\_old, "лет назад ты стал совершеннолетним")
\subsubsection{Бинарное (битовое) представление данных}
После разговора о переполнении, нельзя не сказать о том, что именно переполняется. Далее будут представлены сведения которые касаются не только языка Java но и любого другого языка программирования. Эти сведения помогут разобраться в деталях того как хранится значение переменной в программе и как, в целом, происходит работа компьютерной техники.
Плюсом такого подхода является возможность легко корректировать большие проекты. Представьте, что в вашем коде несколько тысяч строк, а число 18 использовалось несколько десятков раз.
● При развертывании проекта в стране, где совершеннолетием считается 21 год вы будете перечитывать весь код в поисках магических "18" и править их на "21". В случае с константой изменить число нужно в одном месте.
● Дополнительный сложности могут возникнуть, если в коде будет 18 как возраст совершеннолетия и 18 как коэффициент для рассчёт чего-либо. Теперь править кода ещё сложнее, ведь возраст изменился, а коэффициент -нет. В случае с сохранением значений в константы мы снова меняем число в одном месте.
\begin{frm} \info Все современные компьютеры, так или иначе работают от электричества и являются примитивными по своей сути устройствами, которые понимают только два состояния: есть напряжение в электрической цепи или нет. Эти два состояния принято записывать в виде 1 и 0, соответственно. \end{frm}
Все данные в любой программе - это единицы и нули. Данные в программе на Java не исключение, удобнее всего это явление рассматривать на примере примитивных данных. Поскольку в компьютере можно оперировать только двумя значениями то естественным образом используется двоичная система счисления.
\begin{table}[H]
\centering
\begin{tabular}{|r|r|r|r|}
\hline
Десятичное & Двоичное & Восьмеричное & Шестнадцатеричное\\
\hline
00 & 00000 & 00 & 0x00 \\
01 & 00001 & 01 & 0x01 \\
02 & 00010 & 02 & 0x02 \\
03 & 00011 & 03 & 0x03 \\
04 & 00100 & 04 & 0x04 \\
05 & 00101 & 05 & 0x05 \\
06 & 00110 & 06 & 0x06 \\
07 & 00111 & 07 & 0x07 \\
08 & 01000 & 10 & 0x08 \\
09 & 01001 & 11 & 0x09 \\
10 & 01010 & 12 & 0x0a \\
11 & 01011 & 13 & 0x0b \\
12 & 01100 & 14 & 0x0c \\
13 & 01101 & 15 & 0x0d \\
14 & 01110 & 16 & 0x0e \\
15 & 01111 & 17 & 0x0f \\
16 & 10000 & 20 & 0x10 \\
\hline
\end{tabular}
\caption{Представления чисел}
\label{tab:counting-systems}
\end{table}
Двоичная система счисления это система счисления с основанием два. Существуют и другие системы счисления, например, восьмеричная, но сейчас она отходит на второй план полностью уступая своё место шестнадцатеричной системе счисления. Каждая цифра в десятичной записи числа называется разрядом, аналогично в двоичной записи чисел каждая цифра тоже называется разрядом, но для компьютерной техники этот разряд называется битом.
\begin{frm}
\info Одна единица или ноль - это один \textbf{бит} передаваемой или хранимой информации.
\end{frm}
Биты принято собирать в группы по восемь штук, по восемь разрядов, эти группы называются \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 бита хранения информации.
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item длдлдл
\end{enumerate}
\subsubsection{}
\subsection{Базовый функционал языка}
\subsubsection{Математические операторы}
@ -87,7 +166,6 @@ print(how\_old, "лет назад ты стал совершеннолетни
\subsubsection{Бинарные арифметические операторы};
\subsection{Функции}
параметры, возвращаемые значения, перегрузка функций
\subsection*{Задания к семинару}
\begin{itemize}
@ -97,3 +175,160 @@ print(how\_old, "лет назад ты стал совершеннолетни
\end{document}
% таблица «Основные типы данных» & целочисленных типов аж 4 и они занимают 1,2,4,8 байт соответственно. про чар, несмотря на то, что он целочисленный мы поговорим чуть позднее. с четырьмя основными целочисленными типами всё просто - значения в них могут быть только целые, никак и никогда невозможно присвоить им дробных значений, хотя и тут можно сделать оговорку и поклон в сторону арифметики с фиксированной запятой, но мы этого делать не будем, чтобы не взрывать себе мозг и не сбиваться с основной мысли. итак, целочисленные типы с диапазонами минус 128 плюс 127, минус 32768 плюс 32767, я никогда не запомню что там после минус и плюс 2млрд, и четвёртый, который лично я никогда даже не давал себе труд дочитать до конца
% про эти типы важно помнить два факта: инт - это самый часто используемый тип, если сомневаетесь, какой использовать, используйте инт. все числа, которые вы пишете в коде - это инты, даже если вы пытаетесь их присвоить переменной другого типа
% Я вот сказал, что инт самый часто используемый и внезапно подумал: а ведь на практике, чаще всего, было бы достаточно шорта, например, в циклах, итерирующихся по подавляющему большинству коллекций, или при хранении значений, скажем, возраста человека, но всё равно все по привычке используют инт \\ \hline
% byte b = 120; byte b1 = 200; & Теперь плавно подошли к тому что все написанное нами в коде программы цифры - это по умолчанию интеджеры, а дробные даблы, и становится достаточно интересно как они преобразуются например в меньше типы. Тут все просто - если мы пишем цифрами справа число, которое может поместиться в меньший тип слева то статический анализатор кода его пропустит, а компилятор преобразует в меньший тип автоматически. Как мы видим, к маленькому байту вполне успешно присваивается инт. получается, обманул, сказав, что все числа это инты?
% если же мы пишем число которое больше типа слева и соответственно поместиться не может, среда разработки нам выдает сообщение о том что произойдёт переполнение и вообще невозможно положить так много в такой маленький контейнер. А в предупреждении компилятора мы видим, что ожидался байт, а даём мы инт. \\ \hline
% лайвкод в котором нужно показать попытку присвоения лонга, показать предупреждения среды & Интересное начинается когда мы хотим записать в виде числа какое-то значение большее чем может принимать инт, и явно присвоить начальное значение переменной типа лонг. давайте посмотрим на следующий пример - попытку присвоить значение 5 млрд переменной типа лонг. помним, что в лонге можно хранить очень большие числа, мы то явно видим, что слева лонг и точно знаем что присваиваемое значение в него поместится, но среду и компилятор это почему-то мало волнует, значит и тут наврал? давайте разбираться по порядку: если мы посмотрим на ошибку, там английскими буквами будет очень понятно написано - не могу положить такое большое значение в переменную типа инт. а это может значить только одно: справа - инт. не соврал. Почему большой инт без проблем присваивается к маленькому байту? поговорм буквально через несколько минут, пока просто запомним, что это происходит \\ \hline
% \code{long l0 = 3_000_000_000L; float f = 0.123f;} & Аналогичная ситуация с флоутами и даблами. Все дробные числа, написанные в коде - это даблы, поэтому положить их во флоут без дополнительных плясок с бубном невозможно по понятной причине, они туда не помещаются. В этих случаях к написанному справа числу нужно добавить явное указание на его тип, то есть мы как бы говорим компилятору, что мы точно уверены, что справа большой лонг (или маленький флоут, в зависимости от контекста). Это уводит нас в сторону разговора о преобразовании типов, опять же, поговорим об этом через несколько минут, чтобы не отвлекаться от хранения примитивов. Просто запоминаем, что для лонга пишем Л а для флоута ф. Чаще всего л пишут заглавную, чтобы подчеркнуть, что тип большой, а ф пишут маленькую, чтобы подчеркнуть, что мы уменьшаем тип. но регистр значения не имеет, можно писать и так и так.\\ \hline
% Слайд & Далее речь пойдёт о том, что называется числами с плавающей запятой. в англоязычной литературе эти числа называются числа с плавающей точкой (от английского флоутин поинт), такое различие связано с тем, что в русскоязычной литературе принято отделять дробную часть числа запятой, а в европейской и американской - точкой.
% Как мы видим, два из восьми типов не имеют диапазонов значений, это связано с тем, что диапазоны значений флоута и дабла заключаются не в величине возможных хранимых чисел, а в точности этих чисел после запятой. до какого знака будет сохранена точность. Говорить о числах с плавающей точкой и ничего не сказать об особенности их хранения - преступление, поэтому, снова немного отвлечёмся на общее развитие, несколько минут поговорим не о джаве, а о компьютерах в целом. \\ \hline
% много хорошо и подробно, но на С https://habr.com/ ru/post/112953/ \includegraphics[width=30mm]{../pics/jc-02-float01.png} & Работает по стандарту IEEE 754 (1985 года). Для работы с числами с плавающей запятой на аппаратурном уровне к обычному процессору который находится в вашем устройстве ещё прикручивают математический сопроцессор, он нужен, чтобы постоянно вычислять эти ужасные плавающие запятые. Если попытаться уложить весь стандарт в два предложения, то получится примерно следующее: формат подразумевает три поля (знак, 8(11) разрядов поля порядка, 23(52) бита мантисса). Чтобы получить из этой битовой каши число надо $-1$ возвести в степень знака, умножить на 2 в степени порядка минус 127 и умножить на 1 + мантиссу делёную на два в степени размера мантиссы. Формула на экране, она не очень сложная. В остальном, ничего не понятно, но очень интересно, понимаю, давайте попробуем на примере. \\ \hline
% возьмём число +0,5 & с ним всё довольно просто, чтобы получить $+0,5$ нужно 2 возвести в $-1$ степень. поэтому, если развернуть обратно формулу, описанную выше, в знак и мантиссу мы ничего не пишем, оставляем 0, а в порядке должно быть 126, тогда мы должны будем $-1$ возвести в 0ю степень и получить положительный знак, умножить на 2 в степени $126-127 = -1$, получив внезапно 0,5 и умножить на 1 плюс пустая мантисса, в которой по сути не очень важно, что делить, что умножать и в какие степени возводить, всё равно 0 будет. Отсюда становится очевидно, что чем сложнее мантисса и чем меньше порядок, тем более точные и интересные числа мы можем получить. \\ \hline
% а что если -0,15625 & Попробуем немного сложнее: число $-0,15625$, чтобы понять как его записывать, откинем знак, это будет единица в разряде, отвечающем за знак, и посчитаем мантиссу с порядком. представим число как положительное и будем от него последовательно отнимать числа, являющиеся отрицательными степенями двойки, чтобы получить максимально близкое к нулю значение \\ \hline
% $2^{1} = 2$ $2^{0} = 1.0$ $2^{-1} = 0.5$ $2^{-2} = 0.25$ $2^{-3} = 0.125$ $2^{-4} = 0.0625$ $2^{-5} = 0.03125$ $2^{-6} = 0.015625$ $2^{-7} = 0.0078125$ $2^{-8} = 0.00390625$ & получается, что $-1$ и $-2$ степени отнять не получится, мы явно уходим за границу нуля, а вот $-3$ прекрасно отнимается, значит порядок будет $127-3 = 124$, осталось понять, что получается в мантиссе. видим, что оставшееся после первого вычитания число - это 2 в $-5$ степени. значит в мантиссе мы пишем 01 и остальные нули, то есть слева направо указываем, какие степени после $-3$ будут нужны. $-4$ не нужна, а $-5$ нужна. Получится, что \\ \hline
% $(-1)^1 \times 2^{(124-127)} \times (1 + \frac{2097152}{2^{23}}) = 1,15652$
% \vspace{1em}
% $(-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$ & так наше число можно посчитать двумя способами: по приведённой на слайде формуле или последовательно складывая разряды мантиссы умноженные на двойку в степени порядка, уменьшая порядок на каждом шагу, как это показано на слайде \\ \hline
% Особенности \includegraphics[width=30mm]{../pics/jc-02-float02.png} & Ну, что, поковырялись в детальках и винтиках, можно коротко поговорить об особенностях чисел с плавающей точкой, а именно: в числах с плавающей точкой бывает как положительный, так и отрицательный ноль, в отличие от целых чисел, где ноль всегда положительный; у чисел с плавающей запятой есть огромная зона, отмеченная на слайде, которая являет собой непредставимые числа слишком большие для хранения внутри такой переменной или настолько маленькие, что мнимая единица в мантиссе отсутствует; в таком числе можно хранить значения положительной и отрицательной бесконечности; при работе с такими числами появляется понятие не-числа, при этом важно помнить, что NaN != NaN, а если очень сильно постараться, можно хранить там собственные данные, но это выходит далеко за пределы курса, и используется в каких-нибудь чрезвычайно маломощных процессорах для цифровой обработки сигналов, например \\ \hline
% Проблемы \includegraphics[width=30mm]{../pics/jc-02-float03.png} & у чисел с плавающей запятой могут иногда встречаться и проблемы в вычислениях, пример на слайде чрезвычайно грубый, но при работе, например, со статысячными или миллионными долями во флоуте, с такой проблемой вполне можно столкнуться. порядок выполнения действий может влиять на результат выполнения этих действий, что противоречит математике \\ \hline
% Слайд & Задание для самопроверки: \\ \hline
% таблица «Основные типы данных» & Казалось бы, это было так давно, но вернёмся к нашей таблице с примитивными типами данных. Что ещё важного мы видим в этой таблице? шесть из восьми примитивных типов могут иметь как положительные, так и отрицательные значения они называются одним словом «знаковые» типы. Можно заметить что в таблице есть два типа, у которых есть диапазон но нет отрицательных значений, это булин и чар. По порядку с простого, булев тип хранит тру и фолс, тут я вам ничего нового не скажу, на собесах иногда спрашивают сколько места он занимает, в Java объём хранения не определён и зависит от конкретной жвм, обычно считают, что это байт, несмотря на то что хватит и бита, но тогда значительно усложнятся алгоритмы хранения и доступа в коллекциях, но беседа об этом ведёт нас в сложные дебри оптимизации адресации памяти и прочих регистровых алгоритмов и структур данных \\ \hline
% таблица UTF-8 & Что касается чара я нахожу его самым интересным примитивным типом данных. Он единственный беззнаковый целочисленный тип в языке, то есть его старший разряд хранит полезное значение, а не признак положительности. Тип целочисленный но по умолчанию среда исполнения интерпретирует его как символ по таблице utf-8. Таблицу несложно найти в интернете и хранимое в чаре число является индексом в этой таблице, а значит совершенно точно не может быть отрицательным \\ \hline
% Слайд & Вы конечно же об этом уже знаете но именно сейчас важно дополнительно упомянуть о том что в языке Java есть разница между одинарными и двойными кавычками. В одинарных кавычках мы всегда записываем символ который на самом деле является целочисленным значением а в двойных кавычках мы всегда записываем строку, которая фактически является экземпляром класса стринг. Поскольку типизация строгая то мы не можем записывать в чары строки а в строки числа \\ \hline
% Слайд & С типизации вроде разобрались давайте разберёмся с основными понятиями чтобы больше в них никогда не путаться в Java как и в любом другом языке программирования есть три основных понятия, связанных с данными переменными и использованием значений. это объявление присваивание инициализация. Для того чтобы объявить переменную нужно написать её тип и название также часто вместо названия можно встретить термин идентификатор. Далее в любой момент можно присвоить этой переменной значение то есть необходимо написать идентификатор использовать оператор присваивания, который выглядит как обычный знак равенства и справа написать значение которое вы хотите присвоить данной переменной, поставить в конце строки точку с запятой. статический анализатор кода автоматически проверит соответствие типов и при выполнении программы значение будет присвоено. Также существует понятие инициализации - это когда объединяются на одной строке объявление и присваивание. Всё довольно просто и прозрачно. \\ \hline
% преобразование типов & джава это язык со строгой статической типизацией, но преобразование типов в ней всё равно есть. прямо сейчас нам имеет смысл поговорить о преобразовании примитивных типов. преобразование типов - это когда компилятор видит, что типы переменных по разные стороны присваивания разные, помнит, что типизация статическая, и надо как-то решать это противоречие. В разговоре или в сообществах можно услышать термины тайпкастинг, кастинг, каст, кастануть, и другие производные от англ тайпкастинг.\\ \hline
% Слайд & Преобразование типов бывает явное и неявное. Начнём с более простого, неявного. Неявное преобразование типов мы с вами уже даже могли заметить, когда присваивали числа всяким маленьким переменным. Припоминаем,что число справа это инт, а значит 32 разряда, а слева было что-то небольшое, например, байт, и в нём всего 8 разрядов, но ни среда ни компилятор на нас не поругались. потому что значение в большом инте не превысило 8 разрядов маленького байта, и компилятор решил, что раз уж у него все числа в тексте программы инты - нет смысла ругаться на пользователя, он всё равно ничего не исправит. \\ \hline
% Слайд & Итак неявное преобразование типов происходит в случаях, когда, если можно так выразиться, всё и так понятно. В случае, если неявное преобразование невозможно, статический анализатор кода выдаёт нам ошибку, что ожидался один тип, а мы даём другой. \\ \hline
% Слайд & Явное преобразование типов - это когда мы прям пишем в коде, что такая-то переменная должна иметь такой-то тип. Этот вариант типизации мы уже тоже видели, когда дописывали к лонгу Л а к флоуту ф. Но чаще всего случается, что мы присваиваем переменным не те значения, которые пишем в тексте программы, а те, которые получились в результате каких-то вычислений. И часто эти результаты вычислений хранятся в более больших переменных. \\ \hline
% int i = 10; byte b = i; & вот простейший пример, мы совершенно точно уверены, что внутри переменной ай лежит значение не превышающее байт по хранению, и допустим, что точно знаем, что по нашим бизнес-задачам ни в каких вычислениях никогда не сможет это значение превысить, а значит мы можем явно сообщить компилятору, что значение точно поместится в байт. явно преобразовать типы. \\ \hline
% byte b = (byte)i ; & для явного преобразования типов нужно в правой части оператора присваивания перед идентификатором переменной в скобках добавить название типа, к которому мы хотим преобразовать значение этой переменной Преобразование типов, очевидно, затрагивает не только примитивные типы, но и ссылочные, но не будем забегать вперёд, пока остановимся на этом. \\ \hline
% константность & Последнее о примитивах на сегодня - это константность. поскольку мало кто сегодня хорошо умеет в латынь скажу, констаре - это глагол, означающий стоять твёрдо. а значит для математики и языков программирования константность это свойство неизменяемости. в джаве ключевое слово конст не реализовано, хоть и входит в список ключевых. константы же можно создавать при помощи ключевого слова final, что решает довольно забавный парадокс терминологии, ведь от программистов на других языках часто можно часто услышать словосочетание константная переменная, а здесь прямой перевод говорит, что это переменная с конечным значением.\\ \hline
% Слайд & Конечно, ключевое слово файнал возможно применять не только с примитивами, но и со ссылочными типами, методами, классами, но как и в случае с преобразованием типов - не будем забегать вперёд. Пока просто запомним - переменная или идентификатор с конечным значением, именно такая формулировка нам поможет с константностью объектов. \\ \hline
% Слайд & Задание для самопроверки: \\ \hline
% Слайд & Разобравшись с примитивными типами данных мы можем переходить к ссылочным помните я в самом начале говорил что есть два больших вида данных примитивные и Ссылочное вот примитивных восемь а ссылочные это все остальные и это скорее хорошая новость чем плохая потому что не надо запоминать их бесконечные названия. \\ \hline
% Слайд & Самым простым из ссылочных типов является массив. фактически массив выведен на уровень языка и не имеет специального ключевого слова как названия хотя если копнуть гораздо глубже то можно увидеть что у него есть внутреннее название слово эррэй с большой буквы обрамлённое двумя символами нижнего подчёркивания с каждой стороны. Не буду утомлять вас скучной частью о назначении массива и тем что там хранятся наборы однотипных данных, сразу к делу. \\ \hline
% Слайд & Ссылочные типы отличаются от примитивных местом хранения информации. в примитивах данные хранятся прямо там, где существует переменная и где написан её идентификатор, а по идентификатору ссылочного типа внезапно хранится не значение, а ссылка. Эту ссылку можно представить как ярлык у вас на рабочем столе, то есть очевидно, что непосредственная информация хранится не там, где написан идентификатор. Такое явное разделение идентификатора переменной и данных, которые по нему можно найти, нам будет важно помнить и понимать при работе с ООП на дальнейших занятиях. \\ \hline
% Слайд & в идентификаторе массива, фактически, находится адрес его первого элемента. не лишним будет напомнить, что массив - это единая сплошная область данных, в связи с чем в массивах возможно осуществление доступа по индексу. Самый младший индекс любого массива - ноль, поскольку индекс - это значение смещения по элементам относительно начального адреса массива. То есть, для получения самого первого элемента нужно сместиться на ноль шагов. Очевидно, что самый последний элемент в массиве из, скажем, десяти значений, будет храниться по девятому индексу. \\ \hline
% Лайвкод & Массивы в джава создают несколькими способами. В общем виде объявление это тип квадратные скобки как обозначение того, что это будет массив из переменных этого типа, идентификатор. Инициализировать массив можно либо ссылкой на другой массив, пустым массивом или заранее заданными значениями, записанными через запятую в фигурных скобках. Присвоить в процессе работы идентификатору возможно только значение ссылки из другого идентификатора или новый пустой массив. \\ \hline
% Слайд & Давайте, раз уж заговорили о том как создавать поговорим об ограничениях, накладываемых на это действие. Никак и никогда нельзя присвоить идентификатору целый готовый массив в процессе работы, нельзя стандартными средствами переприсвоить ряд значений части массива (так называемые слайсы или срезы). Кстати, получить стандартными средствами срез массива на чтение тоже, к сожалению, нельзя. \\ \hline
% Слайд & Массивы бывают как одномерные, так и многомерные и тут важно помнить, что многомерный массив - это всегда массив из массивов меньшего размера: двумерный массив - это массив одномерный, трёхмерный - массив двумерных и так далее. Правила инициализации у них не отличаются. \\ \hline
% Слайд & преобразовать тип массива нельзя никогда, каждого отдельного элемента можно, а массива целиком нельзя, это связано с тем, что под массивы сразу выделяется непрерывная область памяти, а со сменой типа всех значений массива эту область нужно будет или значительно расширять или значительно сужать, а такую ответственность ЖВМ никогда на себя не возьмёт. Но можно преобразовать тип каждого отдельного элемента массива после его чтения так, как мы это уже делали с примитивами.\\ \hline
% Слайд & если мы пишем ключевое слово файнал с массивом то это совершенно не значит, что мы не сможем изменить значения по индексам этого массива. ключевое слово файнал работает только с идентификаторами. \\ \hline
% Слайд & Есть интересная особенность, она же отличительная черта языка от например С++, она заключается в том, что если вы планируете создавать нижние измерения массива в процессе работы программы, то при инициализации массива верхнего уровня вам не следует указывать размерности нижних уровней. Это связано с тем, что при инициализации джава сразу выделяет память под все измерения, а присваивание нижним измерениям новых значений всё равно будет пересоздавать области памяти, получается небольшая утечка памяти, не критично, но неприятно. Это, кстати, позволяет создавать не прямоугольные массивы.\\ \hline
% Слайд & Прочитать из массива значение возможно обратившись к ячейке массива по индексу. Записать в массив значение возможно обратившись к ячейке массива по индексу, и применив оператор присваивания, тут ничего нового. В каждом объекте массива есть специальное поле, которое обозначает длину данного массива. Поле находится в классе Эррэй и является публичной константой. Это, кстати, хорошо объясняет, почему нужно сразу объявлять длину массива и нельзя менять его значение, вдруг изменится длина, а поле с длиной константно. \\ \hline
% Слайд & Задание для самопроверки: \\ \hline
% Слайд & О данных пока хватит, предлагаю поговорить о базовой функциональности языка, то есть об арифметике, условиях, циклах и бинарных операторах. Здесь будем коротко, потому как совсем уж узких мест тут не предвидится\\ \hline
% Слайд & Математические операторы работают как и предполагается - складывают, вычитают, делят, умножают, делают это по приоритетам известным нам с пятого класса, а если приоритет одинаков - слева направо. Специального оператора возведения в степень как в пайтоне нет. Единственное, что следует помнить, что оператор присваивания продолжает быть оператором присваивания, а не является математическим равенством, а значит сначала посчитается всё, что слева, а потом результат попробует присвоиться переменной справа. Припоминаем что там за дела с целочисленным делением и отбрасыванием дробной части. \\ \hline
% лайвкод & с условиями тоже всё достаточно прозрачно, никаких подводных камней, «если», «иначе если», «в противном случае». раз уж мы тут в шестерёнках копаемся, наверное, следует упомянуть, что конструкция от иф до элс является единым оператором выбора, какой бы длинный он ни был, поэтому надеяться что какие-то входные данные позволят выполниться двум веткам условного оператора немного самонадеяно. каждая ветвь условного оператора - это отдельный кодовый блок со своим окружением и локальными переменными.\\ \hline
% лайвкод & Неплохой альтернативой многоступенчатого оператора иф-элс является оператор свич, который позволяет осуществлять множественный выбор между числовыми значениями. Оператор хорош почти всем, но у него есть ряд особенностей. первая и самая очевидная - это оператор, состоящий из одного кодового блока, то есть сегменты кода находятся в одной области видимости \\ \hline
% лайвкод & если не поставить брейки - будем проваливаться в следующие кейсы, хотя иногда это нужно, но чаще всего является неожиданным поведением. нельзя создать диапазон значений, в отличие от ифчика. нельзя создать локальные переменные с одинаковым названием для каждого кейса.\\ \hline
% Слайд & Циклы представлены в джаве тремя братьями вайл, дувайл и фо. у них также нет каких-то сверхспецифичных особенностей, цикл он и есть цикл, набор повторяющихся действий до наступления условия. вайл - самый простой и примитивный, чаще всего используется, когда нужно описать простой бесконечный цикл. дувайл единственный цикл с постусловием, то есть сначала сделали, а потом решили нужно ли делать ещё раз. используется для ожидания ответов на заданный вопрос и возможного перезапроса по условию. фо - классический счётный цикл, его почему-то программисты любят больше всего. \\ \hline
% Слайд & есть ещё один, активно пропагандируемый цикл - это форич, но я его специально не отнёс к классическим собратьям, поскольку он работает немного неочевидным образом, о чём мы обязательно поговорим позже, поскольку для понимания его работы нам нужно как минимум ознакомиться с ООП и понятием Итератора. \\ \hline
% Слайд & Бинарные операторы. В современных реалиях мегамощных компьютеров вряд ли кто-то задумывается об оптимизации скорости выполнения программы или экономии занимаемой памяти. Но всё меняется, когда программист впервые принимает сложное решение: запрограммировать микроконтроллер или другой «интернет вещей». Там в вашем распоряжении жалкие пара сотен килобайт памяти, если очень повезёт, в которые нужно не только как-то впихнуть текст программы и исполняемый бинарный код, но и какие-то промежуточные, пользовательские и другие данные, буферы обмена и обработки. Другая ситуация, в которой нужно начинать «думать о занимаемом пространстве» это разработка протоколов передачи данных, чтобы протокол был быстрый, не гонял по сети сумасшедшие мегабайты данных и быстро преобразовывался. На помощь приходит натуральная (если можно так выразиться) для информатики система счисления, двоичная, мы о ней говорили в самом начале этой лекции. \\ \hline
% Слайд & Манипуляции двоичными данными представлены в Джава следующими операторами: битовые и-или-не-ксор, сдвиг влево-вправо. литеральные и-или-не вам уже знакомы по условным операторам. Литеральные операции применяются ко всему числовому литералу целиком, а не к каждому отдельному биту. У них особенность заключается в том, как язык программирования интерпретирует числа. В Java, например, в таких операциях может участвовать только тип boolean, а C++ воспринимает любой ненулевой числовой литерал как истину, а нулевой, соответственно, как ложь. Логика формирования значения при этом остаётся такой же, как и при битовых операциях. \\ \hline
% Таблицы истинности & Когда говорят о битовых операциях волей-неволей появляется необходимость поговорить о таблицах истинности. На слайде вы видите таблицы истинности для арифметических битовых операций. \\ \hline
% Примеры в столбик & Битовые операции отличаются тем, что для неподготовленного взгляда они производят почти магические действия. а всё потому, что манипулируют двоичным представлением числа. На слайде вы видите примеры работы арифметических двоичных операторов, если очень внимательно посмотреть. можно увидеть, что соблюдаются показанные только что таблицы истинности \\ \hline
% 0-1-2-4-8-16-32-64-... & С битовыми сдвигами всё куда интереснее, они производят арифметический сдвиг значения слева на количество разрядов, указанное справа, на слайде вы видите числа, интересное свойство этих чисел состоит в том, что в битовом представлении это одна единственная единица, находящаяся в разных разрядах числа.\\ \hline
% Слайд & Заодно это демонстрация сдвига на один разряд влево, и, как следствие, умножение на два. Таким образом, можем сделать вывод о том, что для умножения на 2 в степени Н нужно число сдвинуть на Н разрядов влево \\ \hline
% ...-64-32-16-8-4-2-1-0 & Обратная ситуация со сдвигом вправо, он является целочисленным делением на 2 в степени Н. Весьма удобно и быстро, если не нужны дробные части. Кстати, если посмотреть любой ассемблер любого коммерческого процессора, то можно увидеть, что все умножения и целочисленные деления в коде преобразованы в серию сдвигов и сложений, поскольку выполняются такие операции на простейших АЛУ процессора, без задействования математического сопроцессора, а значит, в разы, а иногда и в десятки раз быстрее.\\ \hline
% $
% X \&\& Y = литеральная
% X || Y = литеральная
% !X = литеральная
% N < < K = N * 2 в степени K
% N >> K = N / 2 в степени K
% x \& y = битовая. 1 если оба x == 1 и y == 1
% x | y = битовая. 1 если хотя бы один из x == 1 или y == 1
% ~x = битовая. 1 если x == 0
% x \^ y = битовая. 1 если x отличается от y
% $ & Резюмируем, ... читаем слайд \\ \hline
% Слайд & Задание для самопроверки: \begin{itemize} \item какое значение будет содержаться в переменной а после выполнения строки инт а = 10.0ф/3.0ф \end{itemize} \\ \hline
% Слайд & Функция - это исполняемый блок кода на языке джава. но в джаве функций не бывает. потому что всё, что мы пишем - находится в классах, даже первый хелловорлд, а функция, принадлежащая классу называется методом. Привыкаем к терминологии, в джаве - только методы, вне классов существовать то есть, что называется, висеть в воздухе, такие блоки кода не могут. \\ \hline
% Слайд & Про функции (и их частный случай в Джаве - методы) важно помнить, что у них - параметры. не аргументы. аргументы - это у вызова функции. а вот у функций - параметры. У функций есть правила именования: функция - это переходный глагол совершенного вида в настоящем времени (вернуть, посчитать, установить, создать), часто снабжаемый дополнением, субъектом действия. методы в джаве пишутся lowerCamelCase то есть первая буква строчная а далее каждое новое слово с большой буквы. Важно, в каком порядке записаны параметры метода, от этого будет зависеть порядок передачи в неё аргументов. \\ \hline
% Слайд & Методы обособлены и их параметры локальны, то есть никакой параметр никакой функции не виден другой функции. Из этого свойства есть очевидное следствие - нельзя писать функции внутри функций. Одна из наиболее частых ошибок новичка - невнимательно посмотреть на открывающие/закрывающие скобки и сильно удивляться тому, что компилятор ругается на синтаксически верно написанную функцию. \\ \hline
% Слайд & Все аргументы в джава передаются копированием, не важно, копирование это числовой константы, числового значения переменной или хранимой в переменной ссылке например на массив. Обратите внимание, что сам объект в метод не копируется, а копируется только его ссылка. Через несколько лекций мы поговорим о том, что в метод можно передать и другой метод, но пока что оставим эту магию в стороне. Важно, что порядок записи аргументов должен строго соответствовать порядку записи параметров функции. \\ \hline
% Вот тут может мне какой-то реквизит понадобится вроде одноразовых тарелок, буду стек вызовов показывать & Возвращаемые из методов значения возникают ровно в том месте, где метод был вызван, это обусловлено архитектурой компьютеров общего назначения и так называемым стеком вызовов. Если мы вызываем несколько методов, а именно это мы чаще всего и делаем в наших программах, то весь контекст исполнения первого метода сохраняется, кладётся (на стек) в стопку уже вызванных методов и процессор идёт выполнять только что вызванный второй метод. по завершении вызванного второго метода мы снимаем со стека лежащий там контекст первого метода, кладём в него вернувшееся из второго метода значение, если оно есть, и продолжаем исполнять первый метод. \\ \hline
% Слайд & В дажва нет вечно запутывающих понятий из С++, поэтому не буду загружать вам голову всякими rvalue, lvalue, xvalue, хоть возвращаемые значения и являются rvalue, главное, запомнить, что вызов метода это по смыслу тоже самое, что подставить в код сразу его возвращаемое значение. Посмотрим внимательно на так хорошо нам знакомую функцию мейн - она в качестве параметра принимает массив строк, а в качестве возвращаемого значения у неё войд. Это кстати отличает джаву от классического С++, где функция мейн возвращает так называемый код завершения программы - целое число, оповещающее ОС о том, штатно ли завершилось приложение\\ \hline
% Слайд & Методы бывают разные, писать их тоже можно по разному, но важно помнить, что джава - это регистрозависимый язык. Что это значит, и почему сейчас? Это значит, что большие буквы это не тоже самое, что маленькие буквы. В методах это особенно важно. \\ \hline
% Слайд & Сигнатура метода — это имя метода и его параметры. В сигнатуру метода не входит возвращаемое значение. Так вот, никак и никогда нельзя написать два метода с одинаковой сигнатурой. А вот с разными - пожалуйста. И здесь мы сталкиваемся с интересным механизмом, который будем обсуждать на некоторых следующих уроках: перегрузка методов. \\ \hline
% Слайд & Перегрузка методов - это механизм языка, позволяющий написать методы с одинаковыми названиями и разными оставшимися частями сигнатуры, чтобы получить некоторое единообразие при вызове семантически схожих методов с разнотипными данными. проще говоря можно назвать методы одинаково, но манипулировать при этом разными типами данных. \\ \hline
% лайвкод & создадим два метода, например, суммирования чисел, при этом суммирование целых будет действительно складывать числа, а суммирование дробных будет просто всегда возвращать 0, так мы явно покажем, что были вызваны совершенно разные функции с их совершенно разными телами \\ \hline
% На этой лекции & мы рассмотрели базовый функционал языка, то есть основную встроенную функциональность, такую как математические операторы, условия, циклы, бинарные операторы. Также разобрали способы хранения и представления данных в Java, и в конце поговорили о способах манипуляции данными, то есть о функциях (в терминах языка называющиеся методами) \\ \hline
% Цель учения — достичь наибольшего удовлетворения в получении знаний. Сюнь-цзы & Надеюсь, на этой лекции вам не было скучно и это не было только лишь повторением того что вы уже знаете. Я постарался добавить максимум полезной информации о всяких шестерёнках под капотом языка, поэтому, закончить хотелось бы словами классика, которые вы видите на слайде.\\ \hline
% \end{longtable}
\end{document}

BIN
pics/jc-02-spanish.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,43 +0,0 @@
\documentclass[../j-spec.tex]{subfiles}
\begin{document}
\subsection{Сценарий урока}
\textit{(несмотря на наличие базовых знаний об ООП, глубоко убеждён, что базовое вступление всё равно нужно, поэтому...)}
Добрый вечер, вот мы с вами и покончили со вступлениями, добравшись до самого интересного. Объектно ориентированное программирование.
Главное, что нам нужно сегодня сделать - это получить понимание. А для этого нам нужно, в первую очередь, расслабиться и не пытаться судорожно запомнить все умные слова которые мы слышим сразу, слова запомнятся сами собой, когда придёт понимание. На деле за аббревиатурой ООП не стоит ничего страшного. Все новички часто пугаются, мол, ООП то, ООП сё, я же призываю вас не думать о сложностях.
Как вы, вероятнее всего, уже слышали и знаете, основа всего языка Java это классы. На классах построен весь язык Java. Все программы, которые мы писали до этого - это тоже классы. Не очень полезные, и особо ничего не делающие, но всё же классы. Самое важное, что надо знать о классах - это то, что классы определяют новый тип данных для нашей программы.
\textbf{нарисовать котика}
Скорее всего, все видят на этой картинке котика? Понятно, что мой художественный талант оставляет желать лучшего, но всё же, это скорее котик, чем, скажем, дом или дерево. Что это значит? То, что у нас в голове есть некоторый шаблон, по которому мы определяем, является-ли объект котиком. Класс это как бы чертёж. Когда мы увидим настоящего котика - мы сразу поймём это, будь он рыжий чёрный или цветной, и какой-бы породы он ни был - мы понимаем, что это кот.
В данной ситуации, кот - это класс. Для объявления класса в Java внезапно используется ключевое слово \code{class} и далее пишется название класса с большой буквы. В общем случае, когда мы пишем большую программу, в которой используем большое количество классов - они все раскидываются по отдельным файлам, и не должны создавать из кода малочитаемую простыню символов. \textbf{Важно, что название публичного класса в файле должно полностью совпадать с названием самого файла, здесь же стоит напомнить о том, что Java - это регистрозависимый язык, то есть заглавные буквы с точки зрения компилятора отличаются от строчных}. Классы обычно представляют модели объектов из реального мира: машина, книга, котик; или некоторые программные абстракции: строка текста, поток ввода, соединение с сервером.
Создадим наш первый класс, котика. У котика, как минимум, должно быть имя, окрас и возраст. Раньше мы работали с уже определёнными типами данных, такими, как инты, байты, стринги и массивы. Теперь у нас есть свой собственный тип данных - кот. Он, как и массив, является ссылочным, но может хранить в себе вот такие разнородные данные, а также содержать методы, но об этом чуточку позже. Как и в случае с массивами, объекты классов надо создавать. Иногда они также называются экземплярами, котик номер один, котик номер два и так далее. Много котиков всё ещё остаются котиками, но каждый из них - отдельный экземпляр. Экземпляр класса - это и есть объект из той самой аббревиатуры “ООП”. Создание экземпляра класса в общем виде выглядит так
\code{Cat c1 = new Cat();}
После выполнения этой инструкции, c1 станет экземпляром класса Cat. Ничего не напоминает? Да именно так мы создавали массивы. Только теперь мы создали не набор однотипных переменных, а набор тех переменных, которые посчитали нужными. Удобно, не правда-ли? По описанному нами шаблону мы теперь можем создать любое количество объектов, экземпляров этого класса, и все они будут независимы друг от друга, если мы явно не укажем обратное. Как мы помним, в нашем классе были три переменных, значит и в нашем объекте они тоже есть. На первый взгляд, может показаться, что мы в правой части этого выражения только лишний раз продублировали название класса, но это не так. На самом дела - это вызов конструктора, но о конструкторах мы также поговорим немного позже, пока разберёмся с тем, что находится внутри экземпляра класса кота.
В переменных хранится так называемое состояние объекта. В методах-же описывается поведение объекта, то есть те вещи, которые он, объект, умеет делать. Наверняка вы помните, как на более ранних уроках вы мучительно не понимали, зачем нам писать отдельные функции и методы, если можно просто взять и написать всю нашу программу строчками подряд? Вот оно - то самое место, где они, функции и методы, очень нужны и важны. Для описания поведения наших классов. Фактически, этим мы и занимались всё время - описывали поведение нашего основного класса. Все экземпляры всех классов имеют свои адреса в памяти и занимают там отдельные области, а идентификатор хранит ссылку на адрес в памяти, где всё это находится.
Рисовать очередной арт-хаус.
С полями разобрались, поговорим о методах. Все мы знаем, что котики умеют мяукать и смешно прыгать. В целях демонстрации мы в описании этих действий просто делать разные выводы в консоль, хотя мы и можем научить нашего котика выбирать минимальное значение из массива, но это было бы, как минимум, неожиданно. Итак опишем метод, например, подать голос и прыгать, а прыгать наш котик будет только если он моложе, скажем, пяти лет. Теперь когда мы хотим позвать нашего котика, он нам скажет, «мяу, я *имя котика*», а если мы решили что котику надо прыгать, он решит, прилично-ли это - прыгать в его возрасте.
Конструкторы классов нужны для нескольких вещей, например, для того, чтобы наш класс сразу что-то сделал при создании. Например,
\code{public Cat () { System.out.println("hello, class"); }}. Шучу, это бесполезно.
Например, чтобы мы могли не создать пустой экземпляр и наполнять его, а чтобы сразу задать ему базовые параметры окраса и имени. Или возраста и окраса, если сделать перегрузку конструктора. Все помнят про перегрузку методов? Тут ситуация точно такая же, в зависимости от типов передаваемых параметров, компилятор выберет нужный конструктор.
Обратите внимание, что мы описываем конструкторы и вызываем именно их в правой части выражения, создающего новые экземпляры котиков. Но, что за конструктор мы видели в самом начале, когда ни о каких конструкторах ещё совсем ничего не знали? Это называется, конструктором по-умолчанию, его создаёт компилятор, если не увидит в описании класса никаких конструкторов. То есть, рассуждения компилятора можно представить себе примерно следующим образом:
\begin{itemize}
\item так, этот программист ничего не знает о конструкторах и о том что у языка полностью объектно-ориентированная природа, добавлю для него пустой конструктор, пусть не думает о моём внутреннем устройстве;
\item о, программист написал какой-то конструктор, значит он знает о том, что это такое и зачем нужно, не буду ему помогать, ему виднее.
\end{itemize}
Из чего мы можем сделать простой вывод: как только мы добавили любой конструктор в наш класс, конструктор по-умолчанию создаваться не будет, а значит, если он нам нужен, придётся его добавить вручную. Зачем может понадобиться конструктор по-умолчанию, поговорим далее.
\end{document}

View File

@ -23,7 +23,7 @@ Java является языком со \textbf{строгой} (также мо
Статическая типизация означает, что у каждой переменной должен быть тип и мы этот тип поменять не можем. Этому свойству противопоставляется динамическая типизация, где мы можем назначить переменной сначала один тип, потом заменить на другой;
Термин явная типизация говорит нам о том, что при создании переменной мы должны ей обязательно присвоить какой-то тип, явно написав это в коде. Бывают языки с неявной типизацией, например, Python, там можно как указать тип, так его и не указывать, язык сам попробуед по контексту догадаться, что вы имели ввиду;
Термин явная типизация говорит нам о том, что при создании переменной мы должны ей обязательно присвоить какой-то тип, явно написав это в коде. В более поздних версиях языка (с 9й) стало возможным инициализировать переменные типа \code{var}, обозначающий нужный тип тогда, когда его возможно однозначно вывести из значения справа. Бывают языки с неявной типизацией, например, Python, там можно как указать тип, так его и не указывать, язык сам попробуед по контексту догадаться, что вы имели ввиду;
Строгая (или иначе сильная) типизация означает, что невозможно смешивать разнотипные данные. Тут есть некоторая оговорка, о которой мы поговорим позже, но с формальной точки зрения язык джава - это язык со строгой типизацией. С другой стороны, существует JavaScript, в котором запись 2 + true выдаст результат 3. \\ \hline
@ -53,7 +53,7 @@ Java является языком со \textbf{строгой} (также мо
Слайд & И каждая цифра в десятичной записи числа называется разрядом собственно в двоичной записи чисел каждая цифра тоже называется разрядом но для компьютерной техники и этот разряд называется битам то есть это 1 б информации либо ноль либо единицу эти биты принято собирать в группы по восемь штук по восемь разрядов эти группы по восемь разрядов называются байт то-есть в языке Java мы можем оперировать Минимальный единицы информации такой как байт для этого даже есть соответствующий тип который так и называется. \\ \hline
Слайд & Внимательный зритель мог обратить внимание что я обозначил диапазон байта как числа от -128 до +127 и не сложно посчитать что 8 байт информации могут в себе содержать ровно 256 значений то есть как раз диапазон от -128 до +127 само число 127 в двоичной записи это семиразрядное число, все разряды которого единицы. Последний восьмой самый старший бит определяет знак числа. \\ \hline
Слайд & Внимательный зритель мог обратить внимание что я обозначил диапазон байта как числа от -128 до +127 и не сложно посчитать что 8 бит информации могут в себе содержать ровно 256 значений то есть как раз диапазон от -128 до +127 само число 127 в двоичной записи это семиразрядное число, все разряды которого единицы. Последний восьмой самый старший бит определяет знак числа. \\ \hline
Слайд & Здесь можно начать долгий и скучный разговор о схемотехнике и хранении отрицательных чисел с применением техники дополнительного кода, но нам достаточно будет знать формулу расчёта записи отрицательных значений. нам нужно в прямой записи поменять все нули на единицы и единицы на нули, и поставить старший бит в единицу, чтобы получить на единицу меньшее отрицательное число, так 0 будет -1, 1 будет -2, 2 станет -3 и так далее. \\ \hline
@ -213,6 +213,8 @@ $ & Резюмируем, ... читаем слайд \\ \hline
лайвкод & создадим два метода, например, суммирования чисел, при этом суммирование целых будет действительно складывать числа, а суммирование дробных будет просто всегда возвращать 0, так мы явно покажем, что были вызваны совершенно разные функции с их совершенно разными телами \\ \hline
На этой лекции & мы рассмотрели базовый функционал языка, то есть основную встроенную функциональность, такую как математические операторы, условия, циклы, бинарные операторы. Также разобрали способы хранения и представления данных в Java, и в конце поговорили о способах манипуляции данными, то есть о функциях (в терминах языка называющиеся методами) \\ \hline
Цель учения — достичь наибольшего удовлетворения в получении знаний. Сюнь-цзы & Надеюсь, на этой лекции вам не было скучно и это не было только лишь повторением того что вы уже знаете. Я постарался добавить максимум полезной информации о всяких шестерёнках под капотом языка, поэтому, закончить хотелось бы словами классика, которые вы видите на слайде.\\ \hline
\end{longtable}

243
scenarios/jtc3-03b.tex Normal file
View File

@ -0,0 +1,243 @@
\documentclass[../j-spec.tex]{subfiles}
\begin{document}
\section{Специализация: ООП}
\begin{longtable}{|p{35mm}|p{135mm}|}
\hline
Экран & Слова \\ \hline
\endhead
Титул & Перейдём к интересному: что можно хранить в джаве, как оно там хранится, и как этим манипулировать \\ \hline
На прошлом уроке & На прошлом уроке мы рассмотрели базовый функционал языка, то есть основную встроенную функциональность, такую как математические операторы, условия, циклы, бинарные операторы. Также разобрали способы хранения и представления данных в Java, и в конце поговорили о способах манипуляции данными, то есть о функциях (в терминах языка называющиеся методами) \\ \hline
На этой лекции & После разбора типов данных попробуем с помощью примеров разобраться, что такое классы и объекты, а также с тем, как применять на практике основные принципы ООП: наследование, полиморфизм и инкапсуляцию. Дополнительно поговорим об устройстве памяти в джава. \\ \hline
Наследование — это передача всех свойств и поведения от одного класса другому, более конкретному. У карася и ерша, как и у всех рыб, есть плавники, хвосты, жабры и чешуя, они живут в воде и плавают;
Инкапсуляция — это размещение данных и методов для их обработки в одном объекте, а также сокрытие деталей его реализации. Мы знаем, как включать и выключать телевизор, переключать программы и регулировать громкость. Для этого не обязательно знать, как он устроен;
Полиморфизм — это проявление одного поведения разными способами. Животные могут издавать звуки, при этом кошка мяукает, а собака лает.
Чуть позже мы рассмотрим эти принципы подробнее. А сейчас разберём некоторые основы, которые мы будем использовать часто в данных принципах. Начнём мы с понятия "Класс".
Что такое класс? Класс определяет форму и сущность объекта и является логической конструкцией, на основе которой построен весь язык Java. Наиболее важная особенность класса состоит в том, что он определяет новый тип данных, которым можно воспользоваться для создания объектов этого типа, т.е. класс — это шаблон (чертеж), по которому создаются объекты (экземпляры класса). Для определения формы и сущности класса указываются данные, которые он должен содержать, а также код, воздействующий на эти данные.
Если мы хотим работать в нашем приложении с документами, то необходимо для начала объяснить что такое документ, описать его в виде класса (чертежа) Document. Рассказать какие у него должны быть свойства: название, содержание, количество страниц, информация о том, кем он подписан и т.д. В этом же классе мы описываем что можно делать с документами: печатать в консоль, подписывать, изменять содержание, название и т.д. Результатом такого описания и будет наш класс Document. Однако это по-прежнему всего лишь чертеж. Если нам нужны конкретные документы, то необходимо создавать объекты: документ №1, документ №2, документ №3. Все эти документы будут иметь одну и ту же структуру (название, содержание, …), с ними можно выполнять одни и те же действия, НО наполнение будет разным (например, в первом документе содержится приказ о назначении работника на должность, во втором, о выдаче премии отделу разработки и т.д.).
Начнём с малого, напишем свой первый класс.
Представим, что нам необходимо работать в нашем приложении с котами. Java ничего не знает о том, что такое коты, поэтому нам необходимо создать новый класс (тип данных), и объяснить что же такое кот.
Создадим проект, его структура нам не в новизну, и будет иметь следующий вид:
Disk:.
├───out
└───src
└───ru
└───gb
└───jcore
Cat.java
Main.java
Теперь начнем потихоньку прописывать класс Cat. Пусть у котов есть три свойства: name (кличка), color (цвет) и age (возраст); и они пока ничего не умеют делать.
Класс Cat имеет следующий вид, и как мы все прекрасно помним, имя класса должно совпадать с именем файла, в котором он объявлен, т.е. класс Cat должен находиться в файле Cat.java:
package ru.gb.jcore;
public class Cat {
String name;
String color;
int age;
}
Итак, мы рассказали Java что такое коты, теперь если мы хотим создать в нашем приложении кота, следует воспользоваться следующим оператором:
Cat cat1 = new Cat();
Подробный разбор того, что происходит в этой строке, будет проведен в следующем пункте. Пока же нам достаточно знать, что мы создали объект типа Cat (экземпляр класса Cat), и для того чтобы с ним работать, положили его в переменную, которой присвоили имя cat1. На самом деле, в переменной не лежит весь объект, а только ссылка где его искать в памяти, но об этом позже.
Объект cat1 создан по чертежу Cat, и значит у него есть поля name, color, age, с которыми можно работать (получать или изменять их значения). Для доступа к полям объекта служит операция-точка, которая связывает имя объекта с именем поля. Например, чтобы присвоить полю color объекта cat1 значение "Белый", нужно выполнить следующий оператор:
cat1.color = "Белый";
Операция-точка служит для доступа к полям и методам объекта по его имени. Рассмотрим пример консольного приложения, работающего с объектами класса Cat. Перейдём в главный класс Main и напишем следующий код:
package ru.gb.jcore;
public class Main{
public static void main(String[] args) {
Cat cat1 = new Cat();
Cat cat2 = new Cat();
cat1.name = "Барсик";
cat1.color = "Белый";
cat1.age = 4;
cat2.name = "Мурзик";
cat2.color = "Черный";
cat2.age = 6;
System.out.println("Кот 1 имя: " + cat1.name + " цвет: " + cat1.color + "
возраст: " + cat1.age);
System.out.println("Кот 2 имя: " + cat2.name + " цвет: " + cat2.color + "
возраст: " + cat2.age);
}
}
Выполним уже известные нам команды для компиляции и запуска приложения:
javac -sourcepath ./src -d out .\src\ru\gb\jcore\Main.java
java -classpath ./out ru.gb.jcore.Main
Выведется:
Кот 1 имя: Барсик цвет: Белый возраст: 4
Кот 2 имя: Мурзик цвет: Черный возраст: 6
Вначале мы создали два объекта типа Cat: cat1 и cat2, соответственно они имеют одинаковый набор полей (name, color, age), однако каждому из них мы в эти поля записали разные значения. Как видно из результата печати в консоле, изменение значения полей одного объекта, никак не влияет на значения полей другого объекта. Данные объектов cat1 и cat2 изолированы друг от друга.
ЧТО ТАКОЕ ОБЪЕКТ
Как создавать новые типы данных (классы) мы разобрались, мельком посмотрели и как создаются объекты наших классов. Давайте теперь поподробнее разберем как создавать объекты, и что при этом происходит
Создание объекта проходит в два этапа. Сначала создается переменная, имеющая интересующий нас тип (в данном случае Cat), в нее мы сможем записать ссылку на будущий объект (поэтому при работе с классами и объектами мы говорим о ссылочных типах данных). Затем необходимо выделить память под наш объект, создать и положить объект в выделенную часть памяти, и сохранить ссылку на этот объект в памяти в нашу переменную.
Для непосредственного создания объекта применяется оператор new, который динамически резервирует память под объект и возвращает ссылку на него, в общих чертах эта ссылка представляет собой адрес объекта в памяти, зарезервированной оператором new.
public static void main(String[] args) {
Cat cat1;
cat1 = new Cat();
}
В первой строке кода переменная cat1 объявляется как ссылка на объект типа Cat и пока ещё не ссылается на конкретный объект (первоначально значение переменной cat1 равно null). В следующей строке выделяется память для объекта типа Cat, и в переменную cat1 сохраняется ссылка на него. После выполнения второй строки кода переменную cat1 можно использовать так, как если бы она была объектом типа Cat. Обычно новый объект создается в одну строку (Cat cat1 = new Cat()).
Теперь немного подробнее рассмотрим оператор new.
Оператор new динамически выделяет память для нового объекта, общая форма применения этого оператора имеет следующий вид:
Имя_класса имя_переменной = new Имя_класса() //на самом деле не имя класса, а название конструктора;
Имя_класса() в правой части выполняет вызов конструктора данного класса, который позволяет подготовить наш объект к работе.
Возможна ситуация, когда две переменные указывают на один и тот же объект в памяти:
public static void main(String[] args) {
Cat cat1 = new Cat();
Cat cat2 = cat1;
cat1.name = "Барсик";
cat1.color = "Белый";
cat1.age = 4;
cat2.age = 5;
System.out.println("Кот 1 имя: " + cat1.name + " цвет: " + cat1.color + " возраст: " + cat1.age);
System.out.println("Кот 2 имя: " + cat2.name + " цвет: " + cat2.color + " возраст: " + cat2.age);
}
На первый взгляд может показаться, что переменной cat2 присваивается ссылка на копию объекта cat1, т.е. переменные cat1 и cat2 будут ссылаться на разные объекты в памяти. Но это не так. На самом деле cat1 и cat2 будут ссылаться на один и тот же объект. Присваивание переменной cat1 значения переменной cat2 не привело к выделению области памяти или копированию объекта, лишь к тому, что переменная cat2 ссылается на тот же объект, что и переменная cat1.
Таким образом, любые изменения, внесённые в объекте по ссылке cat2, окажут влияние на объект, на который ссылается переменная cat1, поскольку это один и тот же объект в памяти, как и в примере выше, где мы указали возраст второго кота 5 лет, а при выводе, возраст 5 лет оказался и у первого кота.
STATIC
Теперь мы знаем что такое класс и объект. На этом моменте хотелось бы остановиться на специальном модификаторе - static - с англ. "статичный", "постоянный" - делает переменную или метод "независимыми" от объекта. Ещё чуть подробнее, то: Static — модификатор, применяемый к полю, блоку, методу или внутреннему классу. Данный модификатор указывает на привязку субъекта к текущему классу.
В таком случае можно воспользоваться ключевым словом static, то есть объявить членов класса статическими. В Java большинство членов служебного класса являются статическими. Вот несколько примеров.
java.util.Objects содержит статические служебные операции для метода объекта;
java.util.Collections состоит исключительно из статических методов, которые работают с коллекциями или возвращают их.
Итак, где же можно употреблять данное ключевое слово?
Мы можем использовать это ключевое слово в четырех контекстах:
статические методы;
статические переменные;
статические вложенные классы;
статические блоки.
Рассмотрим подробнее каждый из перечисленных пунктов.
Статические методы
Статические методы также называются методами класса, потому что статический метод принадлежит классу, а не его объекту. Кроме того, статические методы можно вызывать напрямую через имя класса.
public class CalcExample {
public static void printSum(int a, int b) {
System.out.println(a + b);
}
public void printDifference(int a, int b) {
System.out.println(a - b);
}
public static void main(String[] args) {
/** Вызов статического метода **/
CalcExample.printSum(10, 2);
/** Вызов не-статического метода**/
CalcExample calcExample = new CalcExample();
CalcExample.printDifference(10, 2);
}
}
В приведенном выше примере метод printSum — статический, поэтому его можно вызывать напрямую с именем класса. Нет необходимости создавать новый экземпляр класса CalcExample. Но метод printDifference не является статическим. Таким образом, для нестатического метода необходимо создать новый экземпляр класса CalcExample.
Статические поля
При обозначении переменной уровня класса мы указываем на то, что это значение относится к классу. Если этого не делать, то значение переменной будет привязываться к объекту, созданному по этому классу.
Это значит, что если переменная не статическая, то у каждого нового объекта данного класса будет своё значение этой переменной, меняя которое мы меняем его исключительно в одном объекте:
Например, у нас есть класс котика с нестатической переменной:
public class Cat {
String name;
}
Тогда в мейн класс:
Cat cat1 = new Cat();
cat1.name = "Murka";
Cat cat2 = new Cat();
cat2.name = "Vasya";
System.out.println("First cat - " + cat1.name);
System.out.println("Second cat - " + cat2.name);
Вывод будет следующим:
First cat - Murka
Second cat - Vasya
Как видим, у каждого объекта своя переменная, изменение которой происходит только для этого объекта.
Ну а если у нас переменная статическая, то это глобальное значение — одно для всех:
Теперь мы имеем Cat со статической переменной:
public class Cat {
static String name;
}
По факту переменная у нас одна на всех, и каждый раз мы меняем именно ее.
К статическим переменным, как правило, обращаются не по ссылке на объект — cat1.name, а по имени класса — Cat.name
Соответственно, код из мейн класса после выполнения выведет следующее сообщение:
First cat - Vasya
Second cat - Vasya
К слову, статические переменные — редкость в Java. Вместо них применяют статические константы. Они определяются ключевым словом static final и представлены в верхнем регистре. Вот почему некоторые предпочитают использовать верхний регистр и для статических переменных.
Статические блоки
Статические блоки применяют для инициализации статических переменных. Статический блок выполняется только один раз, когда класс загружается в память. Это происходит, если в коде запрашивается либо объект класса, либо статические члены этого класса.
Ниже пример выведет имя котика:
public class Cat {
public static String name = null;
static {
name = "Murka";
}
public static void main(String[] args) {
System.out.println(name);
}
}
Класс может содержать несколько статических блоков, а каждый из них выполняется в той же последовательности, в которой они написаны в коде.
Последним контекстом использования ключевого слова static - это в части статических вложенных классов, которые мы рассмотрим чуть позднее.
\end{longtable}
\end{document}