03 started
This commit is contained in:
parent
ff36ea14c1
commit
0419b1f1b6
|
@ -0,0 +1,110 @@
|
|||
\documentclass[j-spec.tex]{subfiles}
|
||||
|
||||
\begin{document}
|
||||
%\setcounter{tocdepth}{3}
|
||||
\tableofcontents
|
||||
\section{Специализация: данные и функции}
|
||||
\subsection{В предыдущем разделе}
|
||||
Будет рассмотрен базовый функционал языка, то есть основная встроенная функциональность, такая как математические операторы, условия, циклы, бинарные операторы. Далее способы хранения и представления данных в Java, и в конце способы манипуляции данными, то есть функции (в терминах языка называющиеся методами).
|
||||
|
||||
\subsection{В этом разделе}
|
||||
Разберём такие основополагающих в Java вещи, как классы и объекты, а также с тем, как применять на практике основные принципы ООП: наследование, полиморфизм и инкапсуляцию. Дополнительно рассмотрим устройство памяти в джава.
|
||||
\begin{itemize}
|
||||
\item \nom{класс}{- }
|
||||
\item \nom{объект}{- }
|
||||
\item \nom{статика}{- }
|
||||
\item \nom{стек}{- }
|
||||
\item \nom{куча}{- }
|
||||
\item \nom{сборщик мусора}{- }
|
||||
\item \nom{конструктор}{- }
|
||||
\item \nom{вложенный класс}{- }
|
||||
\item \nom{внутренний класс}{- }
|
||||
\item \nom{инкапсуляция}{- }
|
||||
\item \nom{наследование}{- }
|
||||
\item \nom{полиморфизм }{- }
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\begin{lstlisting}[language=Java,style=JCodeStyle]
|
||||
package ru.gb.jcore;
|
||||
|
||||
public class Cat {
|
||||
String name;
|
||||
String color;
|
||||
int age;
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{lstlisting}[language=Java,style=JCodeStyle]
|
||||
Сat cat0;
|
||||
cat0 = new Cat();
|
||||
Cat cat1 = new Cat();
|
||||
\end{lstlisting}
|
||||
|
||||
|
||||
\begin{lstlisting}[language=Java,style=JCodeStyle]
|
||||
package ru.gb.jcore;
|
||||
|
||||
public class Main{
|
||||
public static void main(String[] args) {
|
||||
Cat cat1 = new Cat();
|
||||
Cat cat2 = new Cat();
|
||||
|
||||
cat1.name = "Barsik";
|
||||
cat1.color = "White";
|
||||
cat1.age = 4;
|
||||
|
||||
cat2.name = "Murzik";
|
||||
cat2.color = "Black";
|
||||
cat2.age = 6;
|
||||
|
||||
System.out.println("Cat1 named: " + cat1.name + " is " + cat1.color + " has age: " + cat1.age);
|
||||
System.out.println("Cat2 named: " + cat2.name + " is " + cat2.color + " has age: " + cat2.age);
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{verbatim}
|
||||
Cat1 named: Barsik is White has age: 4
|
||||
Cat2 named: Murzik is Black has age: 6
|
||||
\end{verbatim}
|
||||
|
||||
\begin{lstlisting}[language=Java,style=JCodeStyle]
|
||||
Cat cat1 = new Cat();
|
||||
Cat cat2 = cat1;
|
||||
|
||||
cat1.name = "Barsik";
|
||||
cat1.color = "White";
|
||||
cat1.age = 4;
|
||||
|
||||
cat2.name = "Murzik";
|
||||
cat2.color = "Black";
|
||||
cat2.age = 6;
|
||||
|
||||
System.out.println("Cat1 named: " + cat1.name + " is " + cat1.color + " has age: " + cat1.age);
|
||||
System.out.println("Cat2 named: " + cat2.name + " is " + cat2.color + " has age: " + cat2.age);
|
||||
\end{lstlisting}
|
||||
\begin{verbatim}
|
||||
Cat1 named: Murzik is Black has age: 6
|
||||
Cat2 named: Murzik is Black has age: 6
|
||||
\end{verbatim}
|
||||
|
||||
\begin{lstlisting}[language=Java,style=JCodeStyle]
|
||||
public class Cat {
|
||||
String name;
|
||||
String color;
|
||||
int age;
|
||||
|
||||
void voice() {
|
||||
System.out.println(name + " meows");
|
||||
}
|
||||
|
||||
void jump() {
|
||||
if (this.age < 5) System.out.println(name + " jumps");
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\printnomenclature[40mm]
|
||||
|
||||
\end{document}
|
233
jtc2-02a.tex
233
jtc2-02a.tex
|
@ -105,6 +105,23 @@
|
|||
\end{center}
|
||||
\end{frm}
|
||||
|
||||
\subsubsection{Задание для самопроверки}
|
||||
\begin{enumerate}
|
||||
\item Возможно ли объявить в Java целочисленную переменную и присвоить ей дробное значение?
|
||||
\item Магическое число - это:
|
||||
\begin{enumerate}
|
||||
\item числовая константа без пояснений;
|
||||
\item число, помогающее в вычислениях;
|
||||
\item числовая константа, присваиваемая при объявлении переменной.
|
||||
\end{enumerate}
|
||||
\item Переполнение переменной - это:
|
||||
\begin{enumerate}
|
||||
\item слишком длинное название переменной;
|
||||
\item слишком большое значение переменной;
|
||||
\item расширение переменной вследствие записи большого значения.
|
||||
\end{enumerate}
|
||||
\end{enumerate}
|
||||
|
||||
\subsubsection{Бинарное (битовое) представление данных}
|
||||
После разговора о переполнении, нельзя не сказать о том, что именно переполняется. Далее будут представлены сведения которые касаются не только языка Java но и любого другого языка программирования. Эти сведения помогут разобраться в деталях того как хранится значение переменной в программе и как, в целом, происходит работа компьютерной техники.
|
||||
|
||||
|
@ -158,7 +175,8 @@
|
|||
|
||||
\subsubsection{Задания для самопроверки}
|
||||
\begin{enumerate}
|
||||
\item длдлдл
|
||||
\item Возможно ли число 3000000000 (3 миллиарда) записать в двоичном представлении?
|
||||
\item Как вы думаете, почему шестнадцатеричная система счисления вытеснила восьмеричную?
|
||||
\end{enumerate}
|
||||
|
||||
\subsubsection{Целочисленные типы}
|
||||
|
@ -296,6 +314,18 @@
|
|||
\item при работе с такими числами появляется понятие не-числа, при этом важно помнить, что \code{NaN != NaN}.
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Задания для самопроверки}
|
||||
\begin{enumerate}
|
||||
\item Сколько байт данных занимает самый большой целочисленный тип?
|
||||
\item Почему нельзя напрямую сравнивать целочисленные данные и числа с плавающей запятой, даже если там точно лежит число без дробной части?
|
||||
\item Внутри переполненной переменной остаётся значение:
|
||||
\begin{enumerate}
|
||||
\item переданное - максимальное для типа;
|
||||
\item максимальное для типа;
|
||||
\item не определено.
|
||||
\end{enumerate}
|
||||
\end{enumerate}
|
||||
|
||||
\subsubsection{Символы и булевы}
|
||||
Шесть из восьми примитивных типов могут иметь как положительные, так и отрицательные значения, они называются \textbf{«знаковые»} типы. В таблице есть два типа, у которых есть диапазон но нет отрицательных значений, это \code{boolean} и \code{char}
|
||||
|
||||
|
@ -389,7 +419,9 @@ Constare - (лат. стоять твёрдо). Константность эт
|
|||
|
||||
\subsubsection{Задания для самопроверки}
|
||||
\begin{enumerate}
|
||||
\item длдлдл
|
||||
\item Какая таблица перекодировки используется для представления символов?
|
||||
\item Каких действий требует от программиста явное преобразование типов?
|
||||
\item какое значение будет содержаться в переменной a после выполнения строки int а = 10.0f/3.0f;
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Ссылочные типы данных, массивы}
|
||||
|
@ -409,7 +441,7 @@ 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}
|
||||
|
||||
\begin{frm} \excl Никак и никогда нельзя присвоить идентификатору целый готовый массив в процессе работы, нельзя стандартными средствами переприсвоить ряд значений части массива (так называемые слайсы или срезы). \end{frm}
|
||||
|
@ -426,18 +458,20 @@ Constare - (лат. стоять твёрдо). Константность эт
|
|||
array[1] = 10;
|
||||
\end{lstlisting}
|
||||
|
||||
В каждом объекте массива есть специальное поле (рис. \hrf{pic:array-length}), которое обозначает длину данного массива. Поле находится в классе \code{__Array__} и является публичной константой.
|
||||
% В каждом объекте массива есть специальное поле (рис. \hrf{pic:array-length}), которое обозначает длину данного массива. Поле находится в классе \code{__Array__} и является публичной константой.
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=12cm]{jc-02-array-length.png}
|
||||
\caption{Константа с длиной массива}
|
||||
\label{pic:array-length}
|
||||
\end{figure}
|
||||
% \begin{figure}[H]
|
||||
% \centering
|
||||
% \includegraphics[width=12cm]{jc-02-array-length.png}
|
||||
% \caption{Константа с длиной массива}
|
||||
% \label{pic:array-length}
|
||||
% \end{figure}
|
||||
|
||||
\subsubsection{Задания для самопроверки}
|
||||
\begin{enumerate}
|
||||
\item длдлдл
|
||||
\item Почему индексация массива начинается с нуля?
|
||||
\item Какой индекс будет последним в массиве из 100 элементов?
|
||||
\item Сколько будет создано одномерных массивов при инициализации массива 3х3?
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Базовый функционал языка}
|
||||
|
@ -486,58 +520,177 @@ Constare - (лат. стоять твёрдо). Константность эт
|
|||
|
||||
Логика формирования значения при этом остаётся такой же, как и при битовых операциях.
|
||||
|
||||
% Таблицы истинности & Когда говорят о битовых операциях волей-неволей появляется необходимость поговорить о таблицах истинности. На слайде вы видите таблицы истинности для арифметических битовых операций. \\ \hline
|
||||
\begin{table}[h!]
|
||||
\centering
|
||||
\begin{tabular}{||c|c|c||}
|
||||
\hline
|
||||
A & B & AND \\ [0.5ex]
|
||||
\hline\hline
|
||||
0 & 0 & 0 \\
|
||||
0 & 1 & 0 \\
|
||||
1 & 0 & 0 \\
|
||||
1 & 1 & 1 \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\hfill
|
||||
\begin{tabular}{||c|c|c||}
|
||||
\hline
|
||||
A & B & OR \\ [0.5ex]
|
||||
\hline\hline
|
||||
0 & 0 & 0 \\
|
||||
0 & 1 & 1 \\
|
||||
1 & 0 & 1 \\
|
||||
1 & 1 & 1 \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\hfill
|
||||
\begin{tabular}{||c|c|c||}
|
||||
\hline
|
||||
A & B & XOR \\ [0.5ex]
|
||||
\hline\hline
|
||||
0 & 0 & 0 \\
|
||||
0 & 1 & 1 \\
|
||||
1 & 0 & 1 \\
|
||||
1 & 1 & 0 \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\hfill
|
||||
\begin{tabular}{||c|c||}
|
||||
\hline
|
||||
A & NOT \\ [0.5ex]
|
||||
\hline\hline
|
||||
0 & 1 \\
|
||||
1 & 0 \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\caption{Таблицы истинности битовых операторов}
|
||||
\label{table:bin-truth-tables}
|
||||
\end{table}
|
||||
|
||||
% Примеры в столбик & Битовые операции отличаются тем, что для неподготовленного взгляда они производят почти магические действия. а всё потому, что манипулируют двоичным представлением числа. На слайде вы видите примеры работы арифметических двоичных операторов, если очень внимательно посмотреть. можно увидеть, что соблюдаются показанные только что таблицы истинности \\ \hline
|
||||
Когда говорят о битовых операциях волей-неволей появляется необходимость поговорить о таблицах истинности. В таблице \hrf{table:bin-truth-tables} вы видите таблицы истинности для арифметических битовых операций. Битовые операции отличаются тем, что для неподготовленного взгляда они производят почти магические действия, потому что манипулируют двоичным представлением числа.
|
||||
|
||||
% 0-1-2-4-8-16-32-64-... & С битовыми сдвигами всё куда интереснее, они производят арифметический сдвиг значения слева на количество разрядов, указанное справа, на слайде вы видите числа, интересное свойство этих чисел состоит в том, что в битовом представлении это одна единственная единица, находящаяся в разных разрядах числа.\\ \hline
|
||||
|
||||
% Слайд & Заодно это демонстрация сдвига на один разряд влево, и, как следствие, умножение на два. Таким образом, можем сделать вывод о том, что для умножения на 2 в степени Н нужно число сдвинуть на Н разрядов влево \\ \hline
|
||||
\begin{figure}[H]
|
||||
\begin{arithmetic}
|
||||
00000100&4\\
|
||||
\code{&} 00000111&7\\
|
||||
00000100&4\\
|
||||
\end{arithmetic}
|
||||
\hfill
|
||||
\begin{arithmetic}
|
||||
00000100&4\\
|
||||
\code{|} 00000111&7\\
|
||||
00000111&7\\
|
||||
\end{arithmetic}
|
||||
\hfill
|
||||
\begin{arithmetic}
|
||||
00000100&4\\
|
||||
\code{^} 00000111&7\\
|
||||
00000011&3\\
|
||||
\end{arithmetic}
|
||||
\hfill
|
||||
\begin{arithmetic}
|
||||
\code{~} 00000100&4\\
|
||||
11111011&-5\\
|
||||
\end{arithmetic}
|
||||
\caption{Бинарная арифметика}
|
||||
\label{fig:bit-ops}
|
||||
\end{figure}
|
||||
|
||||
% ...-64-32-16-8-4-2-1-0 & Обратная ситуация со сдвигом вправо, он является целочисленным делением на 2 в степени Н. Весьма удобно и быстро, если не нужны дробные части. Кстати, если посмотреть любой ассемблер любого коммерческого процессора, то можно увидеть, что все умножения и целочисленные деления в коде преобразованы в серию сдвигов и сложений, поскольку выполняются такие операции на простейших АЛУ процессора, без задействования математического сопроцессора, а значит, в разы, а иногда и в десятки раз быстрее.\\ \hline
|
||||
\begin{table}[h!]
|
||||
\centering
|
||||
\begin{tabular}{||c|c|c||}
|
||||
\hline
|
||||
Число & Бинарное & Сдвиг \\ [0.5ex]
|
||||
\hline\hline
|
||||
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 & 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}
|
||||
|
||||
% $
|
||||
% 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
|
||||
С битовыми сдвигами работать гораздо интереснее и выгоднее. Они производят арифметический сдвиг значения слева на количество разрядов, указанное справа, в таблице \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.
|
||||
\end{itemize}
|
||||
\end{frm}
|
||||
|
||||
\subsubsection{Задания для самопроверки}
|
||||
\begin{enumerate}
|
||||
\item какое значение будет содержаться в переменной а после выполнения строки инт а = 10.0ф/3.0ф
|
||||
\item длдлдл
|
||||
\item Почему нежелательно использовать оператор \code{switch} если нужно проверить диапазон значений?
|
||||
\item Возможно ли записать бесконечный цикл с помощью оператора \code{for}?
|
||||
\item \code{2 + 2 * 2 == 2 << 2 >> 1}?
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Функции}
|
||||
Функция - это исполняемый блок кода на языке джава. но в джаве функций не бывает. потому что всё, что мы пишем - находится в классах, даже первый хелловорлд, а функция, принадлежащая классу называется методом. Привыкаем к терминологии, в джаве нет функции, есть только метод. Вне классов существовать то есть, что называется, висеть в воздухе, такие блоки кода не могут.
|
||||
\textbf{Функция} - это исполняемый блок кода. Функция, принадлежащая классу называется \textbf{методом}.
|
||||
|
||||
% Слайд & Про функции (и их частный случай в Джаве - методы) важно помнить, что у них - параметры. не аргументы. аргументы - это у вызова функции. а вот у функций - параметры. У функций есть правила именования: функция - это переходный глагол совершенного вида в настоящем времени (вернуть, посчитать, установить, создать), часто снабжаемый дополнением, субъектом действия. методы в джаве пишутся lowerCamelCase то есть первая буква строчная а далее каждое новое слово с большой буквы. Важно, в каком порядке записаны параметры метода, от этого будет зависеть порядок передачи в неё аргументов. \\ \hline
|
||||
\begin{lstlisting}[language=Java,style=JCodeStyle]
|
||||
void int method(int param1, int param2) {
|
||||
//function body
|
||||
}
|
||||
|
||||
% Слайд & Методы обособлены и их параметры локальны, то есть никакой параметр никакой функции не виден другой функции. Из этого свойства есть очевидное следствие - нельзя писать функции внутри функций. Одна из наиболее частых ошибок новичка - невнимательно посмотреть на открывающие/закрывающие скобки и сильно удивляться тому, что компилятор ругается на синтаксически верно написанную функцию. \\ \hline
|
||||
public static void main (String[] args) {
|
||||
method(arg1, arg2);
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
% Слайд & Все аргументы в джава передаются копированием, не важно, копирование это числовой константы, числового значения переменной или хранимой в переменной ссылке например на массив. Обратите внимание, что сам объект в метод не копируется, а копируется только его ссылка. Через несколько лекций мы поговорим о том, что в метод можно передать и другой метод, но пока что оставим эту магию в стороне. Важно, что порядок записи аргументов должен строго соответствовать порядку записи параметров функции. \\ \hline
|
||||
При объявлении функции в круглых скобках указываются параметры, а при вызове - аргументы.
|
||||
|
||||
% Вот тут может мне какой-то реквизит понадобится вроде одноразовых тарелок, буду стек вызовов показывать & Возвращаемые из методов значения возникают ровно в том месте, где метод был вызван, это обусловлено архитектурой компьютеров общего назначения и так называемым стеком вызовов. Если мы вызываем несколько методов, а именно это мы чаще всего и делаем в наших программах, то весь контекст исполнения первого метода сохраняется, кладётся (на стек) в стопку уже вызванных методов и процессор идёт выполнять только что вызванный второй метод. по завершении вызванного второго метода мы снимаем со стека лежащий там контекст первого метода, кладём в него вернувшееся из второго метода значение, если оно есть, и продолжаем исполнять первый метод. \\ \hline
|
||||
У функций есть правила именования: функция - это переходный глагол совершенного вида в настоящем времени (вернуть, посчитать, установить, создать), часто снабжаемый дополнением, субъектом действия. Методы в Java пишутся lowerCamelCase. Важно, в каком порядке записаны параметры метода, от этого будет зависеть порядок передачи в неё аргументов. Методы обособлены и их параметры локальны, то есть не видны другим функциям.
|
||||
\begin{frm}
|
||||
\excl Нельзя писать функции внутри других функций.
|
||||
\end{frm}
|
||||
|
||||
% Слайд & В дажва нет вечно запутывающих понятий из С++, поэтому не буду загружать вам голову всякими rvalue, lvalue, xvalue, хоть возвращаемые значения и являются rvalue, главное, запомнить, что вызов метода это по смыслу тоже самое, что подставить в код сразу его возвращаемое значение. Посмотрим внимательно на так хорошо нам знакомую функцию мейн - она в качестве параметра принимает массив строк, а в качестве возвращаемого значения у неё войд. Это кстати отличает джаву от классического С++, где функция мейн возвращает так называемый код завершения программы - целое число, оповещающее ОС о том, штатно ли завершилось приложение\\ \hline
|
||||
Все аргументы передаются копированием, не важно, копирование это числовой константы, числового значения переменной или хранимой в переменной ссылке на массив. Сам объект в метод не копируется, а копируется только его ссылка.
|
||||
|
||||
% Слайд & Методы бывают разные, писать их тоже можно по разному, но важно помнить, что джава - это регистрозависимый язык. Что это значит, и почему сейчас? Это значит, что большие буквы это не тоже самое, что маленькие буквы. В методах это особенно важно. \\ \hline
|
||||
Возвращаемые из методов значения появляются в том месте, где метод был вызван. Если будет вызвано несколько методов, то весь контекст исполнения первого метода сохраняется, кладётся (на стек) в стопку уже вызванных методов и процессор идёт выполнять только что вызванный второй метод. По завершении вызванного второго метода, мы снимаем со стека лежащий там контекст первого метода, кладём в него вернувшееся из второго метода значение, если оно есть, и продолжаем исполнять первый метод.
|
||||
|
||||
% Слайд & Сигнатура метода — это имя метода и его параметры. В сигнатуру метода не входит возвращаемое значение. Так вот, никак и никогда нельзя написать два метода с одинаковой сигнатурой. А вот с разными - пожалуйста. И здесь мы сталкиваемся с интересным механизмом, который будем обсуждать на некоторых следующих уроках: перегрузка методов. \\ \hline
|
||||
\textbf{Вызов метода} - это, по смыслу, тоже самое, что подставить в код сразу его возвращаемое значение.
|
||||
|
||||
% Слайд & Перегрузка методов - это механизм языка, позволяющий написать методы с одинаковыми названиями и разными оставшимися частями сигнатуры, чтобы получить некоторое единообразие при вызове семантически схожих методов с разнотипными данными. проще говоря можно назвать методы одинаково, но манипулировать при этом разными типами данных. \\ \hline
|
||||
\textbf{Сигнатура метода} — это имя метода и его параметры. В сигнатуру метода не входит возвращаемое значение. Нельзя написать два метода с одинаковой сигнатурой.
|
||||
|
||||
% лайвкод & создадим два метода, например, суммирования чисел, при этом суммирование целых будет действительно складывать числа, а суммирование дробных будет просто всегда возвращать 0, так мы явно покажем, что были вызваны совершенно разные функции с их совершенно разными телами \\ \hline
|
||||
\textbf{Перегрузка методов} - это механизм языка, позволяющий написать методы с одинаковыми названиями и разными оставшимися частями сигнатуры, чтобы получить единообразие при вызове семантически схожих методов с разнотипными данными.
|
||||
|
||||
\subsection{Практическое задание}
|
||||
\begin{enumerate}
|
||||
\item Написать метод «Шифр Цезаря», с булевым параметром зашифрования и расшифрования и числовым ключом;
|
||||
\item Написать метод, принимающий на вход массив чисел и параметр n. Метод должен осуществить циклический (последний элемент при сдвиге становится первым) сдвиг всех элементов массива на n позиций;
|
||||
\item Написать метод, которому можно передать в качестве аргумента массив, состоящий строго из единиц и нулей (целые числа типа \code{int}). Метод должен заменить единицы в массиве на нули, а нули на единицы и не содержать ветвлений. Написать как можно больше вариантов метода.
|
||||
\end{enumerate}
|
||||
|
||||
\subsection*{Задания к семинару}
|
||||
\begin{itemize}
|
||||
\item Написать как можно больше вариантов функции инвертирования массива единиц и нулей за 15 минут (без ветвлений любого рода);
|
||||
\item Сравнить без условий две даты, представленные в виде трёх чисел гггг-мм-дд;
|
||||
\end{itemize}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -21,11 +21,26 @@
|
|||
|
||||
Java является языком со \textbf{строгой} (также можно встретить термин «\textbf{сильной}») \textbf{явной} \textbf{статической} типизацией & Что это значит?
|
||||
|
||||
Статическая типизация означает, что у каждой переменной должен быть тип и мы этот тип поменять не можем. Этому свойству противопоставляется динамическая типизация, где мы можем назначить переменной сначала один тип, потом заменить на другой;
|
||||
Статическая типизация означает, что у каждой переменной должен быть тип и мы этот тип поменять не можем. Этому свойству противопоставляется динамическая типизация, где мы можем назначить переменной сначала один тип, потом заменить на другой; Другими словами, в джаве инт всегда останется интом, а в например джаваскрипте вчерашнему инту можно присвоить массив или объект
|
||||
|
||||
Термин явная типизация говорит нам о том, что при создании переменной мы должны ей обязательно присвоить какой-то тип, явно написав это в коде. В более поздних версиях языка (с 9й) стало возможным инициализировать переменные типа \code{var}, обозначающий нужный тип тогда, когда его возможно однозначно вывести из значения справа. Бывают языки с неявной типизацией, например, Python, там можно как указать тип, так его и не указывать, язык сам попробуед по контексту догадаться, что вы имели ввиду;
|
||||
Термин явная типизация говорит нам о том, что при создании переменной мы должны ей обязательно присвоить какой-то тип, явно написав это в коде. В более поздних версиях языка (с 9й) стало возможным инициализировать переменные типа \code{var}, обозначающий нужный тип тогда, когда его возможно однозначно вывести из значения справа. Бывают языки с неявной типизацией, например, Python, там можно как указать тип, так его и не указывать, язык сам попробует по контексту догадаться, что вы имели ввиду; \\ \hline
|
||||
|
||||
Строгая (или иначе сильная) типизация означает, что невозможно смешивать разнотипные данные. Тут есть некоторая оговорка, о которой мы поговорим позже, но с формальной точки зрения язык джава - это язык со строгой типизацией. С другой стороны, существует JavaScript, в котором запись 2 + true выдаст результат 3. \\ \hline
|
||||
лайд
|
||||
%Java - Статическая | Сильная | Явная
|
||||
%C# - Статическая | Сильная | Явная
|
||||
%Java9 - Статическая | Сильная | Неявная
|
||||
%C#4.0 - Статическая | Сильная | Неявная
|
||||
%Haskell - Статическая | Сильная | Неявная
|
||||
%C - Статическая | Слабая | Явная
|
||||
%C++ - Статическая | Слабая | Явная
|
||||
%C++11 - Статическая | Слабая | Неявная
|
||||
%Objective-C - Статическая | Слабая | Явная
|
||||
%Python - Динамическая | Сильная | Неявная
|
||||
%Ruby - Динамическая | Сильная | Неявная
|
||||
%JavaScript - Динамическая | Слабая | Неявная
|
||||
%PHP - Динамическая | Слабая | Неявная
|
||||
%Perl - Динамическая | Слабая | Неявная
|
||||
& Строгая (или иначе сильная) типизация означает, что невозможно смешивать разнотипные данные. Тут есть некоторая оговорка, о которой мы поговорим позже, но с формальной точки зрения язык джава - это язык со строгой типизацией, любая попытка работать в одном выражении с разнотипными данными будет вызывать если не ошибки, то некоторое неопределённое поведение. С другой стороны, существует JavaScript, в котором запись 2 + true выдаст результат 3, а не ошибку. \\ \hline
|
||||
|
||||
таблица «Основные типы данных» & Все данные в Java делятся на две основные категории: примитивные и ссылочные. Чтобы отправить на хранение какие-то данные используется оператор присваивания, который вам всем хорошо знаком.
|
||||
|
||||
|
@ -41,7 +56,16 @@ Java является языком со \textbf{строгой} (также мо
|
|||
|
||||
Лайвкод & если мы создадим переменную скажем байт, диапазон которого от -128 до +127, и присвоим этой переменной значение, скажем, 200, что произойдёт? правильно, переполнение, как если попытаться влить пакет молока в напёрсток, но какое там в нашей переменной останется значение максимальное 127? 200-127? какой-то мусор? именно этими вопросами никогда не надо задаваться, потому что каждый язык, а зачастую и разные компиляторы одного языка ведут себя в этом вопросе по разному. лучше просто не допускать таких ситуаций и проверять все значения на возможность присвоить их своим переменным. В современном мире гигагерцев и терабайтов почти никто не пользуется маленькими типами, их, наверное, можно считать своего рода пережитком, но именно из-за этого ошибки переполнения переменных становятся опаснее испанской инквизиции, их никто не ожидает (тут не помешает кадр из Monty Python «no one expects spanish inqisition») \\ \hline
|
||||
|
||||
Слайд & Задание для самопроверки: \\ \hline
|
||||
Слайд & Задание для самопроверки
|
||||
1. Возможно ли объявить в Java целочисленную переменную и присвоить ей дробное значение?
|
||||
2. Магическое число - это:
|
||||
(a) числовая константа без пояснений;
|
||||
(b) число, помогающее в вычислениях;
|
||||
(c) числовая константа, присваиваемая при объявлении переменной.
|
||||
3. Переполнение переменной - это:
|
||||
(a) слишком длинное название переменной;
|
||||
(b) слишком большое значение переменной;
|
||||
(c) расширение переменной вследствие записи большого значения.\\ \hline
|
||||
|
||||
Бинарное (битовое) представление & При разговоре о переполнении нельзя не упомянуть о том, что же именно переполняется. Несколько минут поговорим о единичках и ноликах в целом, без контекста джавы. Важно помнить, что все компьютеры так или иначе работают от электричества и являются довольно примитивными по сути устройствами, которые понимают только два состояния: есть напряжение в электрической цепи или нет. Эти два состояния принято записывать в виде 1 и 0, соответственно. Отсюда и пошла вся весьма увлекательная работа с бинарными данными. С помощью одних лишь единиц и нулей научились вон какие штуки делать, компьютерами назвали. Итак, все данные в любой программе до изобретения квантовых компьютеров - это единицы и нули. Данные в программе на джава не исключение, и удобнее всего это явление рассматривать, естественно, на примере примитивных данных, о которых мы сейчас и говорим. \\ \hline
|
||||
|
||||
|
@ -49,7 +73,7 @@ Java является языком со \textbf{строгой} (также мо
|
|||
|
||||
Слайд с числами в 10 и 2 & Двоичная система счисления это такая же система счисления как привычные нам десятичная, но с основанием два то есть в привычной нам десятичной системе мы знаем 10 цифр 0123456789 всё остальное это так или иначе составленные из этих цифр числа а в двоичной системе счисления таких цифр только две ноль и один и всё остальное будут составленные из этих цифр числа. \\ \hline
|
||||
|
||||
Слайд с числами в 10 2 и 16 & Существуют и другие системы счисления раньше была очень популярна восьмеричную систему сейчас она отходит на второй план полностью уступая свое место шестнадцатиричной системе счисления которая кстати тоже часто используется в компьютерной техники но сейчас не об этом. \\ \hline
|
||||
Слайд с числами в 10 2 и 16 & Существуют и другие системы счисления раньше была очень популярна восьмеричную систему сейчас она отходит на второй план полностью уступая свое место шестнадцатиричной системе счисления которая кстати тоже часто используется в компьютерной техники но сейчас не об этом. Шестнадцатеричная система счисления позволяет гораздо более компактно записать те же самые сведения о бинарном представлении переменной\\ \hline
|
||||
|
||||
Слайд & И каждая цифра в десятичной записи числа называется разрядом собственно в двоичной записи чисел каждая цифра тоже называется разрядом но для компьютерной техники и этот разряд называется битам то есть это 1 б информации либо ноль либо единицу эти биты принято собирать в группы по восемь штук по восемь разрядов эти группы по восемь разрядов называются байт то-есть в языке Java мы можем оперировать Минимальный единицы информации такой как байт для этого даже есть соответствующий тип который так и называется. \\ \hline
|
||||
|
||||
|
@ -63,7 +87,10 @@ Java является языком со \textbf{строгой} (также мо
|
|||
|
||||
Слайд & Мы иногда будем возвращаться к бинарным представлениям и разным системам счисления, что называется для общего развития. \\ \hline
|
||||
|
||||
Слайд & Задание для самопроверки: \\ \hline
|
||||
УК & Задание для самопроверки \begin{enumerate}
|
||||
\item Возможно ли записать число 3000000000 (3 миллиарда) записать в двоичном представлении? да
|
||||
\item Как вы думаете, почему шестнадцатеричная система счисления вытеснила восьмеричную? компактность записи
|
||||
\end{enumerate} \\ \hline
|
||||
|
||||
таблица «Основные типы данных» & целочисленных типов аж 4 и они занимают 1,2,4,8 байт соответственно. про чар, несмотря на то, что он целочисленный мы поговорим чуть позднее. с четырьмя основными целочисленными типами всё просто - значения в них могут быть только целые, никак и никогда невозможно присвоить им дробных значений, хотя и тут можно сделать оговорку и поклон в сторону арифметики с фиксированной запятой, но мы этого делать не будем, чтобы не взрывать себе мозг и не сбиваться с основной мысли. итак, целочисленные типы с диапазонами минус 128 плюс 127, минус 32768 плюс 32767, я никогда не запомню что там после минус и плюс 2млрд, и четвёртый, который лично я никогда даже не давал себе труд дочитать до конца
|
||||
|
||||
|
@ -99,7 +126,16 @@ $(-1)^1 \times 1,01e-3 = 1\times2^{-3} + 0\times2^{-4} + 1\times2^{-5} = 1\times
|
|||
|
||||
Проблемы \includegraphics[width=30mm]{../pics/jc-02-float03.png} & у чисел с плавающей запятой могут иногда встречаться и проблемы в вычислениях, пример на слайде чрезвычайно грубый, но при работе, например, со статысячными или миллионными долями во флоуте, с такой проблемой вполне можно столкнуться. порядок выполнения действий может влиять на результат выполнения этих действий, что противоречит математике \\ \hline
|
||||
|
||||
Слайд & Задание для самопроверки: \\ \hline
|
||||
Слайд & Задание для самопроверки \begin{enumerate}
|
||||
\item Сколько байт данных занимает самый большой целочисленный тип? 8
|
||||
\item Почему нельзя напрямую сравнивать целочисленные данные и числа с плавающей запятой, даже если там точно лежит число без дробной части? представления
|
||||
\item Внутри переполненной переменной остаётся значение:3
|
||||
\begin{enumerate}
|
||||
\item переданное - максимальное для типа;
|
||||
\item максимальное для типа;
|
||||
\item не определено.
|
||||
\end{enumerate}
|
||||
\end{enumerate}\\ \hline
|
||||
|
||||
таблица «Основные типы данных» & Казалось бы, это было так давно, но вернёмся к нашей таблице с примитивными типами данных. Что ещё важного мы видим в этой таблице? шесть из восьми примитивных типов могут иметь как положительные, так и отрицательные значения они называются одним словом «знаковые» типы. Можно заметить что в таблице есть два типа, у которых есть диапазон но нет отрицательных значений, это булин и чар. По порядку с простого, булев тип хранит тру и фолс, тут я вам ничего нового не скажу, на собесах иногда спрашивают сколько места он занимает, в Java объём хранения не определён и зависит от конкретной жвм, обычно считают, что это байт, несмотря на то что хватит и бита, но тогда значительно усложнятся алгоритмы хранения и доступа в коллекциях, но беседа об этом ведёт нас в сложные дебри оптимизации адресации памяти и прочих регистровых алгоритмов и структур данных \\ \hline
|
||||
|
||||
|
@ -125,7 +161,11 @@ byte b = (byte)i ; & для явного преобразования типов
|
|||
|
||||
Слайд & Конечно, ключевое слово файнал возможно применять не только с примитивами, но и со ссылочными типами, методами, классами, но как и в случае с преобразованием типов - не будем забегать вперёд. Пока просто запомним - переменная или идентификатор с конечным значением, именно такая формулировка нам поможет с константностью объектов. \\ \hline
|
||||
|
||||
Слайд & Задание для самопроверки: \\ \hline
|
||||
Слайд & Задание для самопроверки: \begin{enumerate}
|
||||
\item Какая таблица перекодировки используется для представления символов?
|
||||
\item Каких действий требует от программиста явное преобразование типов?
|
||||
\item какое значение будет содержаться в переменной a после выполнения строки int а = 10.0f/3.0f;
|
||||
\end{enumerate} \\ \hline
|
||||
|
||||
Слайд & Разобравшись с примитивными типами данных мы можем переходить к ссылочным помните я в самом начале говорил что есть два больших вида данных примитивные и Ссылочное вот примитивных восемь а ссылочные это все остальные и это скорее хорошая новость чем плохая потому что не надо запоминать их бесконечные названия. \\ \hline
|
||||
|
||||
|
@ -149,7 +189,11 @@ byte b = (byte)i ; & для явного преобразования типов
|
|||
|
||||
Слайд & Прочитать из массива значение возможно обратившись к ячейке массива по индексу. Записать в массив значение возможно обратившись к ячейке массива по индексу, и применив оператор присваивания, тут ничего нового. В каждом объекте массива есть специальное поле, которое обозначает длину данного массива. Поле находится в классе Эррэй и является публичной константой. Это, кстати, хорошо объясняет, почему нужно сразу объявлять длину массива и нельзя менять его значение, вдруг изменится длина, а поле с длиной константно. \\ \hline
|
||||
|
||||
Слайд & Задание для самопроверки: \\ \hline
|
||||
Слайд & задание для самопроверки \begin{enumerate}
|
||||
\item Почему индексация массива начинается с нуля?
|
||||
\item Какой индекс будет последним в массиве из 100 элементов?
|
||||
\item Сколько будет создано одномерных массивов при инициализации массива 3х3?
|
||||
\end{enumerate} \\ \hline
|
||||
|
||||
Слайд & О данных пока хватит, предлагаю поговорить о базовой функциональности языка, то есть об арифметике, условиях, циклах и бинарных операторах. Здесь будем коротко, потому как совсем уж узких мест тут не предвидится\\ \hline
|
||||
|
||||
|
@ -191,7 +235,11 @@ x | y = битовая. 1 если хотя бы один из x == 1 или y =
|
|||
x \^ y = битовая. 1 если x отличается от y
|
||||
$ & Резюмируем, ... читаем слайд \\ \hline
|
||||
|
||||
Слайд & Задание для самопроверки: \begin{itemize} \item какое значение будет содержаться в переменной а после выполнения строки инт а = 10.0ф/3.0ф \end{itemize} \\ \hline
|
||||
Слайд & Задание для самопроверки: \begin{itemize}
|
||||
\item Почему нежелательно использовать оператор \code{switch} если нужно проверить диапазон значений?
|
||||
\item Возможно ли записать бесконечный цикл с помощью оператора \code{for}?
|
||||
\item \code{2 + 2 * 2 == 2 << 2 >> 1}?
|
||||
\end{itemize} \\ \hline
|
||||
|
||||
Слайд & Функция - это исполняемый блок кода на языке джава. но в джаве функций не бывает. потому что всё, что мы пишем - находится в классах, даже первый хелловорлд, а функция, принадлежащая классу называется методом. Привыкаем к терминологии, в джаве - только методы, вне классов существовать то есть, что называется, висеть в воздухе, такие блоки кода не могут. \\ \hline
|
||||
|
||||
|
@ -217,6 +265,15 @@ $ & Резюмируем, ... читаем слайд \\ \hline
|
|||
|
||||
Цель учения — достичь наибольшего удовлетворения в получении знаний. Сюнь-цзы & Надеюсь, на этой лекции вам не было скучно и это не было только лишь повторением того что вы уже знаете. Я постарался добавить максимум полезной информации о всяких шестерёнках под капотом языка, поэтому, закончить хотелось бы словами классика, которые вы видите на слайде.\\ \hline
|
||||
|
||||
ДЗ & Практическое задание:
|
||||
\begin{enumerate}
|
||||
\item Написать метод «Шифр Цезаря», с булевым параметром зашифрования и расшифрования и числовым ключом;
|
||||
\item Написать метод, принимающий на вход массив чисел и параметр n. Метод должен осуществить циклический (последний элемент при сдвиге становится первым) сдвиг всех элементов массива на n позиций;
|
||||
\item Написать метод, которому можно передать в качестве аргумента массив, состоящий строго из единиц и нулей (целые числа типа \code{int}). Метод должен заменить единицы в массиве на нули, а нули на единицы. Написать как можно больше вариантов метода.
|
||||
\end{enumerate}
|
||||
\\ \hline
|
||||
|
||||
|
||||
\end{longtable}
|
||||
|
||||
\end{document}
|
||||
|
|
|
@ -11,135 +11,63 @@
|
|||
|
||||
На прошлом уроке & На прошлом уроке мы рассмотрели базовый функционал языка, то есть основную встроенную функциональность, такую как математические операторы, условия, циклы, бинарные операторы. Также разобрали способы хранения и представления данных в Java, и в конце поговорили о способах манипуляции данными, то есть о функциях (в терминах языка называющиеся методами) \\ \hline
|
||||
|
||||
На этой лекции & После разбора типов данных попробуем с помощью примеров разобраться, что такое классы и объекты, а также с тем, как применять на практике основные принципы ООП: наследование, полиморфизм и инкапсуляцию. Дополнительно поговорим об устройстве памяти в джава. \\ \hline
|
||||
На этой лекции: классы и объекты; управление памятью; инкапсуляция; наследование; полиморфизм. & После разбора типов данных попробуем с помощью примеров разобраться в таких основополагающих в джава вещах, как классы и объекты, а также с тем, как применять на практике основные принципы ООП: наследование, полиморфизм и инкапсуляцию. Дополнительно поговорим об устройстве памяти в джава. \\ \hline
|
||||
|
||||
Наследование — это передача всех свойств и поведения от одного класса другому, более конкретному. У карася и ерша, как и у всех рыб, есть плавники, хвосты, жабры и чешуя, они живут в воде и плавают;
|
||||
Инкапсуляция — это размещение данных и методов для их обработки в одном объекте, а также сокрытие деталей его реализации. Мы знаем, как включать и выключать телевизор, переключать программы и регулировать громкость. Для этого не обязательно знать, как он устроен;
|
||||
Полиморфизм — это проявление одного поведения разными способами. Животные могут издавать звуки, при этом кошка мяукает, а собака лает.
|
||||
Класс & Начнём с базового, фундаментального понятия класс.\\ \hline
|
||||
|
||||
Чуть позже мы рассмотрим эти принципы подробнее. А сейчас разберём некоторые основы, которые мы будем использовать часто в данных принципах. Начнём мы с понятия "Класс".
|
||||
Что такое класс? Класс определяет форму и сущность объекта и является логической конструкцией, на основе которой построен весь язык Java. Наиболее важная особенность класса состоит в том, что он определяет новый тип данных, которым можно воспользоваться для создания объектов этого типа, т.е. класс — это шаблон (чертеж), по которому создаются объекты (экземпляры класса). Для определения формы и сущности класса указываются данные, которые он должен содержать, а также код, воздействующий на эти данные.
|
||||
Если мы хотим работать в нашем приложении с документами, то необходимо для начала объяснить что такое документ, описать его в виде класса (чертежа) Document. Рассказать какие у него должны быть свойства: название, содержание, количество страниц, информация о том, кем он подписан и т.д. В этом же классе мы описываем что можно делать с документами: печатать в консоль, подписывать, изменять содержание, название и т.д. Результатом такого описания и будет наш класс Document. Однако это по-прежнему всего лишь чертеж. Если нам нужны конкретные документы, то необходимо создавать объекты: документ №1, документ №2, документ №3. Все эти документы будут иметь одну и ту же структуру (название, содержание, …), с ними можно выполнять одни и те же действия, НО наполнение будет разным (например, в первом документе содержится приказ о назначении работника на должность, во втором, о выдаче премии отделу разработки и т.д.).
|
||||
Начнём с малого, напишем свой первый класс.
|
||||
Представим, что нам необходимо работать в нашем приложении с котами. Java ничего не знает о том, что такое коты, поэтому нам необходимо создать новый класс (тип данных), и объяснить что же такое кот.
|
||||
Создадим проект, его структура нам не в новизну, и будет иметь следующий вид:
|
||||
Чертёж (набросок рисунка) кота & Что такое класс? С точки зрения ООП, класс определяет форму и сущность объекта и является логической конструкцией, на основе которой построен весь язык Java. Наиболее важная особенность класса состоит в том, что он определяет новый тип данных, которым можно воспользоваться для создания объектов этого типа, т.е. класс — это шаблон (чертёж), по которому создаются объекты (экземпляры класса). Для определения формы и сущности класса указываются данные, которые он должен содержать, а также код, воздействующий на эти данные.\\ \hline
|
||||
|
||||
Disk:.
|
||||
├───out
|
||||
└───src
|
||||
└───ru
|
||||
└───gb
|
||||
└───jcore
|
||||
Cat.java
|
||||
Main.java
|
||||
Котик и стопки документов & Если мы хотим работать в нашем приложении с документами, то необходимо для начала объяснить приложению, что такое документ, описать его в виде класса (чертежа) Document. Рассказать какие у него должны быть свойства: название, содержание, количество страниц, информация о том, кем он подписан и т.д. В этом же классе мы описываем что можно делать с документами: печатать в консоль, подписывать, изменять содержание, название и т.д. Результатом такого описания и будет класс Document. Однако это по-прежнему всего лишь чертеж.\\ \hline
|
||||
|
||||
Буквы, написанные по трафарету чтобы было видно сам трафарет. документы, одинаковые по структуре и разные по содержанию. & Если нам нужны конкретные документы, а нам они обязательно нужны, то необходимо создавать объекты: документ №1, документ №2, документ №3. Все эти документы будут иметь одну и ту же структуру (название, содержание, ...), с ними можно выполнять одни и те же действия (печатать, подписать, ...) НО наполнение будет разным (например, в первом документе содержится приказ о назначении работника на должность, во втором, о выдаче премии отделу разработки и т.д.). \\ \hline
|
||||
|
||||
Теперь начнем потихоньку прописывать класс Cat. Пусть у котов есть три свойства: name (кличка), color (цвет) и age (возраст); и они пока ничего не умеют делать.
|
||||
Класс Cat имеет следующий вид, и как мы все прекрасно помним, имя класса должно совпадать с именем файла, в котором он объявлен, т.е. класс Cat должен находиться в файле Cat.java:
|
||||
03-Структура & Начнём с малого, напишем свой первый класс. Представим, что нам необходимо работать в нашем приложении с котами. Java ничего не знает о том, что такое коты, поэтому нам необходимо создать новый класс (тип данных), и объяснить что же такое кот. Создадим проект, его структура нам не в новизну, и будет иметь вид как на слайде, в мейне пока что простой хелловорлд, а вот с новым файлом кота пойдём разбираться, Создадим его для простоты в том же пакете, что и мейн \\ \hline
|
||||
|
||||
package ru.gb.jcore;
|
||||
лайвкод 03-кот & Начнем описывать класс Cat. как мы все прекрасно помним, имя класса должно совпадать с именем файла, в котором он объявлен, т.е. класс Cat должен находиться в файле Cat.java. Пусть у котов есть три свойства: name (кличка), color (цвет) и age (возраст); и они пока ничего не умеют делать. Класс Cat будет иметь следующий вид. (String name; String color; int age;)\\ \hline
|
||||
|
||||
public class Cat {
|
||||
String name;
|
||||
String color;
|
||||
int age;
|
||||
}
|
||||
03-экземпляр-кота & Мы рассказали Java что такое коты, теперь если мы хотим создать в нашем приложении конкретного кота, а я напомню, что в 90\% случаев мы сильно хотим создавать те или иные экземпляры, следует воспользоваться оператором new Cat(); в основном классе программы. Более подробно разберём, что происходит в этой строке, чуть позже. Пока же нам достаточно знать, что мы создали объект типа Cat (экземпляр класса Cat), и запомнить эту конструкцию. Для того чтобы с ним (экземпляром) работать, можем положить его в переменную, которой дать идентификатор cat1. \\ \hline
|
||||
|
||||
лайвкод 03-разные-коты & Припоминаем разницу между объявлением, присваиванием и инициализацией, становится понятно, что тут произошло и как ещё можно создавать котов. Припоминаем также, что в переменной не лежит сам объект, а только ссылка на него, подробнее, как и обещал, позже. Объект cat1 создан по чертежу Cat, и значит у него есть поля name, color, age, с которыми можно работать (получать или изменять их значения). Для доступа к полям объекта служит оператор точка, которая связывает имя объекта с именем поля. Например, чтобы присвоить полю color объекта cat1 значение "Белый", нужно выполнить следующий код: cat1.color = "Белый"; Прошу, не запутайтесь, класс кота мы описали в отдельном файле, а создавать объекты и совершать манипуляции следует в мейне, не может же кот сам себе имя назначить \\ \hline
|
||||
|
||||
Итак, мы рассказали Java что такое коты, теперь если мы хотим создать в нашем приложении кота, следует воспользоваться следующим оператором:
|
||||
лайвкод 03-два-кота & Операция-точка служит для доступа к полям и методам объекта по его имени. Рассмотрим пример консольного приложения, работающего с объектами класса Cat. создадим двух котов, один будет белым барсиком 4х лет, второй чёрным мурзиком шести лет, и просто выведем информацию о них в терминал \\ \hline
|
||||
|
||||
Cat cat1 = new Cat();
|
||||
03-класс-объекты1 & Вначале мы создали два объекта типа Cat: cat1 и cat2, соответственно они имеют одинаковый набор полей name, color, age, почему? потому что они принадлежат одному классу, созданы по одному шаблону. Однако каждому из них мы в эти поля записали разные значения. Как видно из результата печати в консоли, изменение значения полей одного объекта, никак не влияет на значения полей другого объекта. Данные объектов cat1 и cat2 изолированы друг от друга. А значит мы делаем вывод о том, поля хранятся в классе, а значения полей хранятся в объектах. \\ \hline
|
||||
|
||||
Объекты & Как создавать новые типы данных (классы) мы разобрались, мельком посмотрели и как создаются объекты наших классов \\ \hline
|
||||
|
||||
Подробный разбор того, что происходит в этой строке, будет проведен в следующем пункте. Пока же нам достаточно знать, что мы создали объект типа 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 = new Cat(); & Подробнее разберем как создавать объекты, и что при этом происходит. Создание объекта как любого ссылочного типа данных проходит в два этапа. Мы это помним из рассказа о массивах. Сначала создается переменная, имеющая интересующий нас тип, в нее мы можем записать ссылку на объект. Затем необходимо выделить память под наш объект, создать и положить объект в выделенную часть памяти, и сохранить ссылку на этот объект в памяти в нашу переменную. Для непосредственного создания объекта применяется оператор new, который динамически резервирует память под объект и возвращает ссылку на него, в общих чертах эта ссылка представляет собой адрес объекта в памяти, зарезервированной оператором new. \\ \hline
|
||||
|
||||
03-разные-коты & В первой строке кода переменная cat1 объявляется как ссылка на объект типа Cat и пока ещё не ссылается на конкретный объект (первоначально значение переменной cat1 равно null). В следующей строке выделяется память для объекта типа Cat, и в переменную cat1 сохраняется ссылка на него. После выполнения второй строки кода переменную cat1 можно использовать так, как если бы она была объектом типа Cat. Обычно новый объект создается в одну строку (Cat cat1 = new Cat()). \\ \hline
|
||||
|
||||
В первой строке кода переменная cat1 объявляется как ссылка на объект типа Cat и пока ещё не ссылается на конкретный объект (первоначально значение переменной cat1 равно null). В следующей строке выделяется память для объекта типа Cat, и в переменную cat1 сохраняется ссылка на него. После выполнения второй строки кода переменную cat1 можно использовать так, как если бы она была объектом типа Cat. Обычно новый объект создается в одну строку (Cat cat1 = new Cat()).
|
||||
Теперь немного подробнее рассмотрим оператор new.
|
||||
Оператор new динамически выделяет память для нового объекта, общая форма применения этого оператора имеет следующий вид:
|
||||
Оператор new
|
||||
|
||||
Имя_класса имя_переменной = new Имя_класса() //на самом деле не имя класса, а название конструктора;
|
||||
[квалификаторы] ИмяКласса имяПеременной = new ИмяКласса();
|
||||
& Раз уж начали про объекты - нельзя не сказать про оператор new. Оператор new динамически выделяет память для нового объекта, общая форма применения этого оператора имеет вид как на слайде, но на самом деле справа - не имя класса, как могло показаться на первый взгляд ИмяКласса() в правой части выполняет вызов конструктора данного класса, который подготавливает вновь создаваемый объект к работе. \\ \hline
|
||||
|
||||
лайвкод 03-один-кот & Именно от оператора нью будет зависеть, сколько именно объектов будет создано в программе. На первый взгляд может показаться, что переменной cat2 присваивается ссылка на копию объекта cat1, т.е. переменные cat1 и cat2 будут ссылаться на разные объекты в памяти. Но это не так. На самом деле cat1 и cat2 будут ссылаться на один и тот же объект. Присваивание переменной cat1 значения переменной cat2 не привело к выделению области памяти или копированию объекта, лишь к тому, что переменная cat2 содержит ссылку на тот же объект, что и переменная cat1.\\ \hline
|
||||
|
||||
Имя_класса() в правой части выполняет вызов конструктора данного класса, который позволяет подготовить наш объект к работе.
|
||||
Возможна ситуация, когда две переменные указывают на один и тот же объект в памяти:
|
||||
03-один-кот-2 & Таким образом, любые изменения, внесённые в объекте по ссылке cat2, окажут влияние на объект, на который ссылается переменная cat1, поскольку это один и тот же объект в памяти, как и в примере на слайде, где мы как будто бы указали возраст второго кота 6 лет, а при выводе, возраст 6 лет оказался и у первого кота.
|
||||
\\ \hline
|
||||
|
||||
public static void main(String[] args) {
|
||||
Cat cat1 = new Cat();
|
||||
Cat cat2 = cat1;
|
||||
Метод - это функция, принадлежащая классу & Ранее мы уже говорили о том, что в языке Java любая программа состоит из классов и функций, которые могут описываться только внутри них. Именно поэтому все функции в языке Java являются методами. А метод, как мы помним, это - функция, являющаяся частью некоторого класса, которая может выполнять операции над данными этого класса. \\ \hline
|
||||
|
||||
cat1.name = "Барсик";
|
||||
cat1.color = "Белый";
|
||||
cat1.age = 4;
|
||||
03-нестатик & Метод для своей работы может использовать поля объекта и/или класса, в котором определен, напрямую, без необходимости передавать их во входных параметрах. Это похоже на использование глобальных переменных в функциях, но в отличие от глобальных переменных, метод может получать прямой доступ только к членам класса. Самые простые методы работают с данными объектов.\\ \hline
|
||||
|
||||
cat2.age = 5;
|
||||
Лайвкод 03-метод & Вернёмся к примеру с котиками. Все мы знаем, что котики умеют урчать, мяукать и смешно прыгать. В целях демонстрации мы в описании этих действий просто будем делать разные выводы в консоль, хотя мы и можем научить нашего котика выбирать минимальное значение из массива, но это было бы неожиданно. Итак опишем метод например подать голос и прыгать. \\ \hline
|
||||
|
||||
System.out.println("Кот 1 имя: " + cat1.name + " цвет: " + cat1.color + " возраст: " + cat1.age);
|
||||
System.out.println("Кот 2 имя: " + cat2.name + " цвет: " + cat2.color + " возраст: " + cat2.age);
|
||||
}
|
||||
Лайвкод 03-метод-вызов & Обращение к методам выглядит очень похожим на стандартный способом, через точку, как к полям. Теперь когда мы хотим позвать нашего котика, он нам скажет, мяу, я имя котика, а если мы решили что котику надо прыгать, он решит, прилично-ли это - прыгать в его возрасте. Как видно, барсик замечательно прыгает, а мурзик от прыжков воздержался, хотя попрыгать мы попросили их обоих \\ \hline
|
||||
|
||||
шрифтом курьер слово static
|
||||
|
||||
На первый взгляд может показаться, что переменной cat2 присваивается ссылка на копию объекта cat1, т.е. переменные cat1 и cat2 будут ссылаться на разные объекты в памяти. Но это не так. На самом деле cat1 и cat2 будут ссылаться на один и тот же объект. Присваивание переменной cat1 значения переменной cat2 не привело к выделению области памяти или копированию объекта, лишь к тому, что переменная cat2 ссылается на тот же объект, что и переменная cat1.
|
||||
викисловарь - статика этимология & Теперь, когда мы более-менее хорошо знаем, что такое класс и объект, хотелось бы остановиться на специальном модификаторе - static, делающем переменную или метод "независимыми" от объекта. Если формально, то: Static — модификатор, применяемый к полю, блоку, методу или внутреннему классу, он указывает на привязку субъекта к текущему классу. Для использования таких полей и методов, соответственно, объект создавать не нужно. В Java большинство членов служебных классов являются статическими.\\ \hline
|
||||
|
||||
Таким образом, любые изменения, внесённые в объекте по ссылке cat2, окажут влияние на объект, на который ссылается переменная cat1, поскольку это один и тот же объект в памяти, как и в примере выше, где мы указали возраст второго кота 5 лет, а при выводе, возраст 5 лет оказался и у первого кота.
|
||||
STATIC
|
||||
Теперь мы знаем что такое класс и объект. На этом моменте хотелось бы остановиться на специальном модификаторе - static - с англ. "статичный", "постоянный" - делает переменную или метод "независимыми" от объекта. Ещё чуть подробнее, то: Static — модификатор, применяемый к полю, блоку, методу или внутреннему классу. Данный модификатор указывает на привязку субъекта к текущему классу.
|
||||
В таком случае можно воспользоваться ключевым словом static, то есть объявить членов класса статическими. В Java большинство членов служебного класса являются статическими. Вот несколько примеров.
|
||||
|
||||
java.util.Objects содержит статические служебные операции для метода объекта;
|
||||
java.util.Collections состоит исключительно из статических методов, которые работают с коллекциями или возвращают их.
|
||||
|
||||
Итак, где же можно употреблять данное ключевое слово?
|
||||
\begin{itemize}
|
||||
\item статические методы;
|
||||
\item статические переменные;
|
||||
\item статические вложенные классы;
|
||||
\item статические блоки.
|
||||
\end{itemize} &
|
||||
Мы можем использовать это ключевое слово в четырех контекстах:
|
||||
|
||||
статические методы;
|
||||
|
@ -147,96 +75,164 @@ java.util.Collections состоит исключительно из стати
|
|||
статические вложенные классы;
|
||||
статические блоки.
|
||||
|
||||
Рассмотрим подробнее каждый из перечисленных пунктов.
|
||||
Статические методы
|
||||
Статические методы также называются методами класса, потому что статический метод принадлежит классу, а не его объекту. Кроме того, статические методы можно вызывать напрямую через имя класса.
|
||||
Рассмотрим подробнее только первые два пункта, о третьем поговорим чуть позже, а четвёртый потребует от нас знаний, выходящих не только за этот урок, но и за десяток следующих. \\ \hline
|
||||
|
||||
public class CalcExample {
|
||||
public static void printSum(int a, int b) {
|
||||
System.out.println(a + b);
|
||||
}
|
||||
Статические методы - методы класса & Статические методы также называются методами класса, потому что статический метод принадлежит классу, а не его объекту. Что логично, нестатические называются методами объекта. Статические методы обладают интересным свойством - их можно вызывать напрямую через имя класса, не обращаясь к объекту и вообще объект не создавая. Что это и зачем нужно? Например, умение кота мяукать можно вывести в статическое поле, потому что, например, мы весной можем открыть окно, не увидеть ни одного экземпляра котов, но зато услышать их, и точно знать, что мяукают не дома и не машины, а коты \\ \hline
|
||||
|
||||
public void printDifference(int a, int b) {
|
||||
System.out.println(a - b);
|
||||
}
|
||||
03-статические-поля & Аналогично статическим методам, статические поля принадлежат классу и совершенно ничего не знают об объектах. Важной отличительной чертой статических полей является то, что их значения также хранятся в классе, в отличие от обычных полей, чьи значения хранятся в объектах. На слайде довольно понятно это показано. Изображение на слайде именно в этом виде я настоятельно рекомендую если не заучить, то хотя бы хорошо запомнить, оно нам ещё пригодится. Из этой же картинки можно сделать несколько выводов, о которых сейчас поговорим \\ \hline
|
||||
|
||||
public static void main(String[] args) {
|
||||
/** Вызов статического метода **/
|
||||
CalcExample.printSum(10, 2);
|
||||
лайвкод 03-статическое-поле-код & Помимо того, что статические поля - это полезный инструмент создания общих свойств это ещ§ и опасный инструмент создания общих свойств. Так, например, мы знаем, что у котов четыре лапы, а не 6 и не 8. Не создавая никакого барсика будет понятно, что у кота - 4 лапы. Это полезное поведение \\ \hline
|
||||
|
||||
/** Вызов не-статического метода**/
|
||||
CalcExample calcExample = new CalcExample();
|
||||
CalcExample.printDifference(10, 2);
|
||||
}
|
||||
}
|
||||
лайвкод 03-статическое-поле-ошибка & Посмотрим на опасность. Мы видим, что у каждого кота есть имя, и помним, что коты хранят значение своего имени каждый сам у себя. А знают экземпляры о названии поля потому что знают, какого класса они экземпляры. Но что если мы по невнимательности добавим свойство статичности к имени кота? \\ \hline
|
||||
|
||||
|
||||
В приведенном выше примере метод printSum — статический, поэтому его можно вызывать напрямую с именем класса. Нет необходимости создавать новый экземпляр класса CalcExample. Но метод printDifference не является статическим. Таким образом, для нестатического метода необходимо создать новый экземпляр класса CalcExample.
|
||||
Статические поля
|
||||
При обозначении переменной уровня класса мы указываем на то, что это значение относится к классу. Если этого не делать, то значение переменной будет привязываться к объекту, созданному по этому классу.
|
||||
Это значит, что если переменная не статическая, то у каждого нового объекта данного класса будет своё значение этой переменной, меняя которое мы меняем его исключительно в одном объекте:
|
||||
Например, у нас есть класс котика с нестатической переменной:
|
||||
03-статическое-поле-признак & Создав тех же самых котов, которых мы создавали весь урок, мы получим двух мурзиков и ни одного барсика. Почему это произошло? По факту переменная у нас одна на всех, и значение тоже одно, а значит каждый раз мы меняем именно его, а все остальные коты ничего не подозревая смотрят на значение общей переменной и бодро его возвращают. Поэтому, чтобы не запутаться, к статическим переменным, как правило, обращаются не по ссылке на объект — cat1.name, а по имени класса — Cat.name. \\ \hline
|
||||
|
||||
public class Cat {
|
||||
String name;
|
||||
}
|
||||
03-статические-поля & К слову, статические переменные — редкость в Java. Вместо них применяют статические константы. Они определяются ключевыми словами static final и по соглашению о внешнем виде кода пишутся в верхнем регистре. \\ \hline
|
||||
|
||||
Введение в управление памятью & Понимая поверхностно, как организовано создание и хранение объектов, можем углубиться в эту тему. Это факультативная часть, выходящая достаточно далеко за рамки джуниор позиции. \\ \hline
|
||||
|
||||
03-память & Это глубокое погружение в управление памятью Java позволит расширить ваши знания о том, как работает куча, ссылочные типы и сборка мусора. Поможет лучше понять глубинные процессы и, как следствие, писать более хорошие программы. Для оптимальной работы приложения JVM делит память на область стека (stack) и область кучи (heap). Всякий раз, когда мы объявляем новые переменные, создаем объекты или вызываем новый метод, JVM выделяет память для этих операций в стеке или в куче. Далее будет представлена модель организации памяти в Java. Чуть позже мы её рассмотрим подробнее, а начнем со стека. \\ \hline
|
||||
|
||||
стопка блинов LIFO (Last-In, First-Out. Последний-зашел, Первый-вышел) & Стековая память отвечает за хранение ссылок на объекты кучи и за хранение типов значений (также известных в Java как примитивные типы), которые содержат само значение, а не ссылку на объект из кучи. Данная память в Java работает по схеме LIFO (Последний-зашел-Первый-вышел).\\ \hline
|
||||
|
||||
НУЖЕН РЕКВИЗИТ ТРИ ТАРЕЛКИ С ПЕЧЕНЬЯМИ ИЛИ КОНФЕТАМИ & Кроме того, переменные в стеке имеют определенную область видимости. Программой используются только объекты из активной области. Например, если ЖВМ выполняет тело метода, она помещает весь используемый в методе контекст на стек и может получить доступ только к объектам из стека, которые находятся внутри тела метода. Она не может получить доступ к другим локальным переменным, так как они не выходят в область видимости. Когда метод завершается и возвращается результат его работы, верхняя часть стека выталкивается, и активная область видимости изменяется. \\ \hline
|
||||
|
||||
03-многопоточность & Немного забегая вперёд можно сказать, что все потоки, работающие в JVM, имеют свой стек. Для нас пока достаточно отождествлять поток и собственно исполнение нашей программы. Стек в свою очередь держит информацию о том, какие методы вызвал поток. Я буду называть это «стеком вызовов». Стек вызовов возобновляется, как только поток завершает выполнение своего кода. каждый слой стека вызовов содержит все локальные переменные для вызываемого метода и потока. Все локальные переменные примитивных типов полностью хранятся в стеке потоков и не видны другим потокам \\ \hline
|
||||
|
||||
на слайд перечисление справа
|
||||
& Особенности стека:
|
||||
\begin{itemize}
|
||||
\item Он заполняется и освобождается по мере вызова и завершения новых методов;
|
||||
\item Переменные на стеке существуют до тех пор, пока выполняется метод в котором они были созданы;
|
||||
\item Если память стека будет заполнена, Java бросит исключение java.lang.StackOverflowError;
|
||||
\item Доступ к этой области памяти осуществляется быстрее, чем к куче;
|
||||
\item Является потокобезопасным, поскольку для каждого потока создается свой отдельный стек.
|
||||
\end{itemize}\\ \hline
|
||||
|
||||
03-устройство памяти & Куча содержит все объекты, созданные в вашем приложении, независимо от того, какой поток создал объект. Неважно, был ли объект создан и присвоен локальной переменной или создан как переменная-член другого объекта, он хранится в куче. со всеми своими примитивными и не примитивными данными внутри. В случае, когда локальная переменная примитивного типа, она хранится на стеке потока.\\ \hline
|
||||
|
||||
03-началось & Локальная переменная также может быть ссылкой на объект. В этом случае ссылка (локальная переменная) хранится на стеке, но сам объект хранится в куче. Объект использует методы, эти методы содержат локальные переменные. Эти локальные переменные также хранятся на стеке, несмотря на то, что объект, который использует метод, хранится в куче. Переменные-члены класса хранятся в куче вместе с самим классом. Это верно как в случае, когда переменная-член имеет примитивный тип, так и в том случае, если она является ссылкой на объект. Статические переменные класса также хранятся в куче вместе с определением класса.
|
||||
В общем случае, эти объекты имеют глобальный доступ и могут быть получены из любого места программы. \\ \hline
|
||||
|
||||
\begin{itemize}
|
||||
\item Young generation
|
||||
\item Old (Tenured) Generation
|
||||
\item Permanent Generation
|
||||
\end{itemize} & Куча разбита на несколько более мелких частей, называемых поколениями:
|
||||
Young Generation — область где размещаются недавно созданные объекты. Когда она заполняется, происходит быстрая сборка мусора;
|
||||
Old (Tenured) Generation — здесь хранятся долгоживущие объекты. Когда объекты из Young Generation достигают определенного порога «возраста», они перемещаются в Old Generation;
|
||||
Permanent Generation — эта область содержит метаинформацию о классах и методах приложения, но начиная с Java 8 данная область памяти была упразднена. В Java 8 PermGen заменён на Metaspace - его динамически изменяемый по размеру аналог. Важно упоминуть, что именно здесь живут статические поля. \\ \hline
|
||||
|
||||
Особенности кучи: список из правой части &
|
||||
\begin{itemize}
|
||||
\item В общем случае, размеры кучи на порядок больше размеров стека
|
||||
\item Когда эта область памяти полностью заполняется, Java бросает java.lang.OutOfMemoryError;
|
||||
\item Доступ к ней медленнее, чем к стеку;
|
||||
\item Эта память, в отличие от стека, автоматически не освобождается. Для сбора неиспользуемых объектов используется сборщик мусора;
|
||||
\item В отличие от стека, куча не является потокобезопасной и ее необходимо контролировать, правильно синхронизируя код.
|
||||
\end{itemize} \\ \hline
|
||||
|
||||
Сборщик мусора & Вроде разобрались, разделили память так, как её разделяет ЖВМ. Предлагаю взглянуть на то, как ЖВМ осуществляет управление неиспользуемыми объектами \\ \hline
|
||||
& \\ \hline
|
||||
& \\ \hline
|
||||
|
||||
|
||||
Тогда в мейн класс:
|
||||
|
||||
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
|
||||
\begin{itemize}
|
||||
\item Этот процесс запускается автоматически Java, и Java решает, запускать или нет этот процесс;
|
||||
\item На самом деле это дорогостоящий процесс. При запуске сборщика мусора все потоки в вашем приложении приостанавливаются (в зависимости от типа GC, который будет обсуждаться позже);
|
||||
\item На самом деле это более сложный процесс, чем просто сбор мусора и освобождение памяти.
|
||||
\end{itemize}
|
||||
Несмотря на то, что Java решает, когда запускать сборщик мусора, вы можете явно вызвать System.gc() и ожидать, что сборщик мусора будет запускаться при выполнении этой строки кода, верно?
|
||||
|
||||
Это ошибочное предположение.
|
||||
|
||||
Вы только как бы просите Java запустить сборщик мусора, но, опять же, Java решать, делать это или нет. В любом случае явно вызывать System.gc() не рекомендуется.
|
||||
|
||||
Поскольку это довольно сложный процесс и может повлиять на вашу производительность, он реализован разумно. Для этого используется так называемый процесс «Mark and Sweep». Java анализирует переменные из стека и «отмечает» все объекты, которые необходимо поддерживать в рабочем состоянии. Затем все неиспользуемые объекты очищаются.
|
||||
|
||||
Фактически, чем больше мусора и чем меньше объектов помечены как живые, тем быстрее идет процесс. Чтобы сделать это еще более оптимизированным, память кучи на состоит из нескольких частей, как было показано на картинке с организацией памяти в Java.
|
||||
|
||||
Давайте пройдёмся по поколениям.
|
||||
|
||||
### Сборщик мусора. Молодое поколение.
|
||||
С высокого уровня все новые объекты начинаются с молодого поколения. Как только они выделены в коде Java, они попадают конкретно в этот подраздел, называемый eden space. В конце концов пространство эдема заполняется предметами. На этом этапе происходит незначительное событие сборки мусора. Некоторые объекты (те, на которые есть ссылки) помечены, а некоторые (те, на которые нет ссылок) - нет. Те, которые были отмечены, затем переходят в другой подраздел молодого поколения под названием S0 пространства выживших (обратите внимание, что само пространство выживших разделено на две части, S0 и S1). Те, которые остались немаркированными, удаляются автоматической сборкой мусора Java.
|
||||
|
||||
![jc-03-gc01](uploads/6ed12a38aeaa5648bb55a34d86b7e2b2/jc-03-gc01.png)
|
||||
|
||||
Так будет продолжаться до тех пор, пока пространство eden снова не заполнится; на этом этапе начинается новый цикл. События предыдущего абзаца повторяются, но в этом цикле все немного по-другому. S0 был заполнен, и поэтому все отмеченные объекты, которые выживают как из пространства eden, так и из S0, фактически попадают во вторую часть пространства survivor, называемую S1. На приведенной ниже диаграмме мы видим, что они помечены как **из пространства выживших** и **в пространство выживших** соответственно.
|
||||
|
||||
![jc-03-gc02](uploads/6ed12a38aeaa5648bb55a34d86b7e2b2/jc-03-gc02.png)
|
||||
|
||||
Следует отметить одну очень важную вещь: любые объекты, попадающие в пространство выживших, помечаются счетчиком возраста. Алгоритм проверит это, чтобы увидеть, соответствует ли он пороговому значению для перехода к следующему этапу: старое поколение (чуть позже доберёмся до этого).
|
||||
|
||||
При следующем второстепенном GC повторяется тот же процесс. Однако на этот раз пространства выживших переключаются. Объекты, на которые даны ссылки, перемещаются в S0.
|
||||
|
||||
![jc-03-gc03](uploads/6ed12a38aeaa5648bb55a34d86b7e2b2/jc-03-gc03.png)
|
||||
|
||||
Главная мысль в том, что объекты не обязательно переходят из S0 в S1 пространства выживших. На самом деле, они просто чередуются с тем, куда они переключаются при каждом незначительном событии сборки мусора.
|
||||
|
||||
Если эти процессы обобщить, то по существу все новые объекты начинаются в пространстве eden, а затем в конечном итоге попадают в пространство survivor, поскольку они переживают циклы сборки мусора.
|
||||
|
||||
### Сборщик мусора. Старое поколение.
|
||||
|
||||
Старое поколение можно рассматривать как место, где лежат долгоживущие объекты. По сути, если объекты достигают определенного возрастного порога после нескольких событий сборки мусора в молодом поколении, то затем они могут быть перемещены в старое поколение.
|
||||
|
||||
Когда объекты собирают мусор из старого поколения, происходит крупное событие сборки мусора.
|
||||
|
||||
Предлагаю рассмотреть, как выглядит продвижение из пространства выживших молодого поколения в старое поколение.
|
||||
|
||||
![jc-03-gc04](uploads/6ed12a38aeaa5648bb55a34d86b7e2b2/jc-03-gc04.png)
|
||||
|
||||
В приведенном выше примере все выжившие объекты, достигшие возрастного порога в 8 циклов — и это всего лишь пример, поэтому специально не запоминайте это число — перемещаются алгоритмом в старое поколение.
|
||||
|
||||
Старое поколение состоит только из одной секции, называемой постоянным поколением.
|
||||
|
||||
### Сборщик мусора. Постоянное поколение.
|
||||
|
||||
Внимание! Постоянное поколение **не** заполняется, когда объекты старого поколения достигают определенного порога, а затем перемещаются (повышаются) в постоянное поколение.
|
||||
|
||||
Скорее, постоянное поколение немедленно заполняется JVM метаданными, которые представляют классы и методы приложений во время выполнения.
|
||||
|
||||
JVM иногда может следовать определенным правилам для очистки постоянного поколения, и когда это происходит, это называется **полной сборкой мусора**.
|
||||
|
||||
Также, хотелось бы упомянуть событие под названием *остановить мир*. Когда происходит небольшая сборка мусора (для молодого поколения) или крупная сборка мусора (для старого поколения), мир останавливается; другими словами, все потоки приложений полностью останавливаются и должны ждать завершения события сборки мусора.
|
||||
|
||||
### Сборщик мусора. Реализации
|
||||
|
||||
Стоит упомянуть, что JVM имеет пять типов реализаций GC:
|
||||
|
||||
- Последовательный сборщик мусора. Это самая простая реализация GC, поскольку она в основном работает с одним потоком. В результате эта реализация GC замораживает все потоки приложения при запуске. Поэтому не рекомендуется использовать его в многопоточных приложениях, таких как серверные среды;
|
||||
|
||||
- Параллельный сборщик мусора. Это GC по умолчанию для JVM, который иногда называют сборщиками пропускной способности. В отличие от последовательного сборщика мусора, он использует несколько потоков для управления пространством кучи, но также замораживает другие потоки приложений во время выполнения GC. Если мы используем этот GC, мы можем указать максимальные потоки сборки мусора и время паузы, пропускную способность и занимаемую площадь (размер кучи);
|
||||
|
||||
- Сборщик мусора CMS. Реализация Concurrent Mark Sweep (CMS) использует несколько потоков сборщика мусора для сбора мусора. Он предназначен для приложений, которые предпочитают более короткие паузы при сборке мусора и могут позволить себе совместно использовать ресурсы процессора со сборщиком мусора во время работы приложения. Проще говоря, приложения, использующие этот тип GC, в среднем реагируют медленнее, но не перестают отвечать, чтобы выполнить сборку мусора. Здесь следует отметить, что, поскольку этот GC является параллельным, вызов явной сборки мусора, такой как использование System.gc() во время работы параллельного процесса, приведет к сбою / прерыванию параллельного режима;
|
||||
|
||||
- Сборщик мусора G1. Сборщик мусора G1 (Garbage First) предназначен для приложений, работающих на многопроцессорных компьютерах с большим объемом памяти. Он доступен с обновления 4 JDK7 и в более поздних версиях. Сборщик G1 заменит сборщик CMS, поскольку он более эффективен;
|
||||
|
||||
- Z сборщик мусора. ZGC (Z Garbage Collector) - это масштабируемый сборщик мусора с низкой задержкой, который дебютировал в Java 11 в качестве экспериментального варианта для Linux. JDK 14 представил ZGC под операционными системами Windows и macOS. ZGC получил статус production начиная с Java 15. ZGC выполняет всю дорогостоящую работу одновременно, не останавливая выполнение потоков приложений более чем на 10 мс, что делает его подходящим для приложений, требующих низкой задержки.
|
||||
|
||||
Теперь, пройдя часть со сборщиком мусора, давайте немного подытожим разницу между Стеком и Кучей:
|
||||
|
||||
- Куча используется всеми частями приложения в то время как стек используется только одним потоком исполнения программы;
|
||||
- Всякий раз, когда создается объект, он всегда хранится в куче, а в памяти стека содержится ссылка на него. Память стека содержит только локальные переменные примитивных типов и ссылки на объекты в куче;
|
||||
- Объекты в куче доступны с любой точки программы, в то время как стековая память не может быть доступна для других потоков;
|
||||
- Управление памятью в стеке осуществляется по схеме LIFO;
|
||||
- Стековая память существует лишь какое-то время работы программы, а память в куче живет с самого начала до конца работы программы;
|
||||
- Также, хотелось бы отметить, что мы можем использовать -Xms и -Xmx опции JVM, чтобы определить начальный и максимальный размер памяти в куче. Для стека определить размер памяти можно с помощью опции -Xss;
|
||||
- Если память стека полностью занята, то Java Runtime бросает java.lang.StackOverflowError, а если память кучи заполнена, то бросается исключение java.lang.OutOfMemoryError: Java Heap Space;
|
||||
- Размер памяти стека намного меньше памяти в куче. Из-за простоты распределения памяти (LIFO), стековая память работает намного быстрее кучи.
|
||||
& \\ \hline
|
||||
& \\ \hline
|
||||
& \\ \hline
|
||||
& \\ \hline
|
||||
|
||||
|
||||
Как видим, у каждого объекта своя переменная, изменение которой происходит только для этого объекта.
|
||||
Ну а если у нас переменная статическая, то это глобальное значение — одно для всех:
|
||||
Теперь мы имеем 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}
|
||||
|
||||
|
|
|
@ -71,3 +71,42 @@
|
|||
\setlist{nolistsep}
|
||||
\setlist[itemize]{leftmargin=10mm}
|
||||
\setlist[enumerate]{leftmargin=10mm}
|
||||
|
||||
\makeatletter
|
||||
\providecommand\text\mbox
|
||||
\newenvironment{arithmetic}[1][]{\begin{tabular}[#1]{Al}}{\end{tabular}}
|
||||
\newcolumntype{A}{>{\bgroup\def~{\phantom{0}}$\@testOptor}r<{\@gobble\\$\egroup}}
|
||||
\def\@testOptor\ignorespaces#1#2\\{%
|
||||
\ifx#1\times
|
||||
\@OperatorRow{#1}{#2}\@tempa%
|
||||
\else\ifx#1+
|
||||
\@OperatorRow+{#2}\@tempa%
|
||||
\else\ifx#1\discretionary% detects the soft hyphen, \-
|
||||
\@ShortSubtractRow{#2}\@tempa%
|
||||
\else\ifx#1-
|
||||
\@OperatorRow-{#2}\@tempa%
|
||||
\else
|
||||
\@NormalRow{#1#2}\@tempa%
|
||||
\fi\fi\fi\fi
|
||||
\@tempa}
|
||||
\def\@OperatorRow#1#2#3{%
|
||||
\@IfEndRow#2\@gobble\\{%
|
||||
\def#3{\underline{{}#1 #2}\\}%
|
||||
}{%
|
||||
\def#3{\underline{{}#1 #2{}}}%
|
||||
}}
|
||||
|
||||
\def\@NormalRow#1#2{%
|
||||
\@IfEndRow#1\@gobble\\{%
|
||||
\def#2{#1\\}%
|
||||
}{%
|
||||
\def#2{#1{}}%
|
||||
}}
|
||||
|
||||
\def\@IfEndRow#1\@gobble#2\\#3#4{%
|
||||
\ifx#2\@gobble
|
||||
#4%
|
||||
\else
|
||||
#3%
|
||||
\fi}
|
||||
\makeatother
|
||||
|
|
Loading…
Reference in New Issue