Показаны сообщения с ярлыком JAVA. Показать все сообщения
Показаны сообщения с ярлыком JAVA. Показать все сообщения

воскресенье, 23 октября 2022 г.

Наследование в Java

   «родительское/дочернее»

    Наследование (inheritance) - свойство системы, позволяющее описать (создать) новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью.
    Класс, от которого производится наследование, называется базовым, родительским или суперклассом, а новый класс - потомком, наследником, дочерним или производным классом. 
    Используется для быстрой и безопасной организации родственных понятий: чтобы было достаточно на каждом иерархическом шаге учитывать только изменения, не дублируя всё остальное, учтённое на предыдущих шагах.

    Общий смысл наследования заключается в том, что если несколько классов имеют сходное поведение, то нет смысла дублировать их описание (писать с нуля), лучше выделить у них общие признаки и объединить их в общем для них родительском классе. При этом в описании самих классов оставить только различающиеся элементы (методы, поля) либо переопределить имеющиеся новой реализацией.

 

    Для обозначения наследования в Java служит слово extends.

    Так или иначе, но наследование всегда используется при создании любого класса, пусть и в не явном виде, т.к. любой класс в Java автоматически становится производным от суперкласса Object. Таким образом мы получаем доступ ко всем полям и методам этого класса.

   Чем дальше вверх по иерархии наследования, тем более универсальными и абстрактными становятся классы. Такие классы становятся основой для других классов. И, как правило, запрещается создавать их экземпляры.

 

В Java есть два вида наследования:

  • наследование классов: каждый наследник может иметь только одного родителя;
  • наследование интерфейсов: интерфейс может иметь сколько угодно родителей.

Порядок инициализации объектов при наследовании

  • память, выделенная под новый объект, заполняется двоичными нулями;

  • в начале идет подъем до корня иерархии, а потом сверху вниз вызываются конструкторы один за другим вплоть до класса, конструируемого объекта;

  • инициализируются поля класса в порядке их записи;

  • вызывается тело конструктора нужного объекта.

    Это делается для того, что бы быть уверенным, что все поля базовых классов проинициализированы, т.к. они доступны в нужном объекте, который имеет к ним доступ.

 

Ограничения

  • при наследовании доступ из методов класса-потомка к приватным полям родительского класса напрямую запрещен. Кроме того, данные поля не наследуются. Но благодаря специальным публичным методам, которые называются get/геттеры и set/сеттеры можно совершенно свободно обращаться к данным полям родительского класса из класса-потомка;

  • приватные методы, как и приватные поля также не наследуются. Это значит, что создание метода в классе-потомке с именем, аналогичным имени метода класса-предка — создаст совершенно новый метод и компилятор не предупредит вас об этом. Во избежание таких коллизий при наследовании методов желательно использовать аннотацию @Override. Благодаря данной аннотации компилятор сможет проконтролировать ваш код и выдать предупреждение, если переопределяемый метод не будет найден в родительском классе.

     

Достоинства

  • способствует уменьшению повторяемости кода, т.е. имеет место быть его переиспользование (англ. code reuse);

  • ускоряет разработку. тк наследование позволяет взять готовый класс, "клонировать" его в новый класс-потомок, т.е. получить весь функционал класса-предка, а затем расширить его, добавив новые методы и поля;

Недостатки

  • большое значение имеет правильное построение иерархии классов. Т.к на поздних этапах разработки, когда иерархия классов построена и на её основе разработано большое количество кода, оказывается трудно или даже невозможно внести какие-либо изменения в код базовых классов иерархии;

  • при внесении изменений в базовые классы — классы наследники об этом могут ничего не знать;

  • данный механизм требует, чтобы точный тип объекта был известен уже на стадии компиляции, что делает код, зависящим от реализации;

  • подкласс зависит от реализации родительского класса, что делает код сильно связанным.

Вместо наследования можно использовать композицию / агрегацию, т.к. этот механизм более гибок, так как позволяет динамически выбирать тип.

 

Когда нужно применять наследование

    Для того что бы определить стоит ли применять наследование нужно для предка и предполагаемого производного класса попробовать установить отношение "является" ("is a").

    Отношение "является" служит признаком наследования.


    Наследование применяют для описания объектов, незначительно отличающихся друг от друга

    При наследовании в классе-потомке должна добавляться функциональность, отличающаяся от существующей в классе-предке. Если в наследнике часть функциональности убирается, то это является поводом задуматься о необходимости в данной ситуации наследования.

суббота, 1 октября 2022 г.

Форматирование строк в Java. System.out.printf . Описание спецификаторов формата %

   Форматирование строк используется если есть шаблонный текст, в некоторых местах которого нужно вставлять значения, которые могут быть разными и приходить в качестве аргументов извне.

    В Java существуют, например, следующие методы для форматирования строк:

 

   1 метод format класса String:

public static String format(String format, Object… args)

   (возвращает строку, отформатированную из строки format с помощью остальных аргументов args)

 

   1 String.format()

   2 System.out.printf()

   3 System.out.format()

 

   Метод format класса String: public static String format(String format, Object… args) возвращает строку, отформатированную из строки format с помощью остальных аргументов args.


   Метод printf() это часть java.io.PrintStream класса.

   Синтакс может быть следующим:

      System.out.printf(format, arguments);
      System.out.printf(locale, format, arguments);


   Внутри printf() использует класс java.util.Formatter для разбора строки формата и создания вывода. Дополнительные параметры строки формата можно найти в документации Formatter Javadoc.


   Правила форматирования определяются параметром форматирования (format)

   Правила (спецификаторы) формата начинаются с символа % и заканчиваются символом, указывающим тип аргумента, который нужно отформатировать (conversion-character). Спецификаторы формата могут (опционально) содержать такие параметры как flags, width, precision.

   %[flags][width][.precision]conversion-character

 

[flags] - флаги - определяют стандартные способы изменения вывода и чаще всего используются для форматирования целых чисел и чисел с плавающей запятой.

[width] - ширина - указывает ширину поля для вывода аргумента. Он представляет собой минимальное количество символов, записываемых на выходе.

[.precision] - точность - указывает количество разрядов точности при выводе значений с плавающей запятой. Кроме того, мы можем использовать его для определения длины подстроки для извлечения из строки.

 

   Пример: System.out.printf("Hello %s!%n", "World");

 

   %s для форматирования (вывода) объектов - строк

   %d для вывода целого числа (int. byte, short, int, long, BigInteger)

   %f для вывода десятичного числа с плавающей точкой 

    %b для вывода любого типа, который будет приведен к boolean

    %t для форматирования значений даты/времени

    %n используется для разделения строки на линии (как Enter)


   %s

   Если попробовать вставить, к примеру, double в место, в котором прописан объект строки, double будет приведен к строке:

   То есть данная запись

String str = String.format("Вася - %s! Он сейчас %s", 18.1, "на работе");

   Выведет следующее:

   Вася - 18.1! Он сейчас на работе

 

   %d

      Пример:

         String.format("Поймал рыб штук %d!",25)

         Результат: Поймал рыб штук 25!

 

   %f

      System.out.printf("%f", Math.PI); // 3,141593

   Вывод десятичного числа с точкой и заданием количества символов после точки.

   Например, для десятичного числа с 3 символами после запятой:

      System.out.printf("%.3f", Math.PI); // 3,142

 

    %b

      (true — если значение не null, false — если null)

      Пример:

         String.format("2x2=5 %b!",null)

         Результат: 2x2=5 false!

 


   Равнозначные примеры:

1 String str = String.format("Вася - %s! Он сейчас %s", "инженер", "на работе");

   System.out.println(str);

2 System.out.printf("Вася - %s! Он сейчас %s", "инженер", "на работе");

3 System.out.format("Вася - %s! Он сейчас %s", "инженер", "на работе");

   Все три примера выведут в консоль следующее:

   Вася - инженер! Он сейчас на работе

 

   Дополнительную информацию можно посмотреть здесь:

https://www.baeldung.com/java-printstream-printf

среда, 10 августа 2022 г.

Оператор ветвления if..else в Java

   Оператор с условием "Если" - if.

    В Java оператор if может сопровождаться дополнительным оператором else, который выполняется при ложном логическом выражениив результате.

   Синтаксис:

   if (Логическое выражение) { 

      //Выполняется, если истинно

    } else { //Выполняется, если ложно }

 

   Объединяющие условие "и" выглядит так:

 if (a && b)

 

   Объединяющие условие "или" выглядит так:

if (a || b)

суббота, 6 августа 2022 г.

Операции в Java

Операция присвоения =
 
  Операция "=" позволяет присвоить значение переменной
   (Пример: int x=3; )
 

Арифметические преобразования

   Арифметические преобразования обозначаются так:

   +   сложение
   -   вычитание
   *   умножение
   /   деление
   %   взятие остатка от деления: выдает остаток от деления: (5%3=2); (24%7=3);

   (Пример: double x3 = 1.1 * 2 + 1;  )

   NB!: При выполнении арифметических операций над операндами с различными типами данных результат будет иметь наибольший тип из типов данных операнд.
    При выполнении арифметических операций операнды всегда преобразуются как
минимум в int (например при умножении двух переменных типа byte оба значения сначала преобразуются в int, и результат выражения будет int).

   При выполнении арифметической операции над операндами разных типов результат операции будет иметь наибольший тип, Что можно описать следующими правилами:

 1. Если один из операндов имеет тип double, то результат выражения
    имеет тип double, иначе смотри пункт 2.
 2. Если один из операндов имеет тип float, то результат выражения имеет
    тип float, иначе смотри пункт 3.
 3. Если один из операндов имеет тип long, то результат выражения имеет
    тип long, иначе результат выражения имеет тип int.

(например, при сложении int  и long  результат будет иметь тип long, а при сложении long  и float  результат будет иметь тип float, а при сложении float  и double  результат будет иметь тип double).

   Если результат операции с целочисленными данными выходит за диапазон, то старшие биты отбрасываются, и результирующее значение будет совершенно неверным. При попытке деления на 0 возникает исключение java.lang.ArithmeticException/zero.

   При выполнении операций с плавающей точкой при выходе за верхнюю или
нижнюю границу диапазона получается +Infinity  (
Double.POSITIVE_INFINITY  и Float.POSITIVE_INFINITY) и -Infinity  (
Double.NEGATIVE_INFINITY  и Float.NEGATIVE_INFINITY ) соответственно, а при получении слишком маленького числа, которое не может быть нормально сохранено в этом типе данных получается -0.0 или +0.0.

   При выполнении операций с плавающей точкой результат NaN  ( Double.NaN и Float.NaN) получается в следующих случаях:

  * Когда один из операндов |NaN|
  * В неопределённых результатах:
      o Деления 0/0, ∞/∞, ∞/−∞, −∞/∞,  −∞/−∞
      o Умножения 0×∞ and 0×−∞
      o Степень 1^∞
      o сложения ∞ + (−∞), (−∞) + ∞ и эквивалентные вычитания.
  * Операции с комплексными результатами:
      o Квадратный корень из отрицательного числа
      o Логарифм отрицательного числа
      o Тангенс 90 градусов и ему подобных (или π/2 радиан)
      o Обратный синус и косинус от числа меньше −1 и больше +1.



Унарные операции

   Унарными называются операции, которые имеют только один операнд. Унарные
операции бывают префиксные и постфиксные.

   Постфиксные унарные операции ставятся после операнда:

  * Инкремент (увеличение на 1) ++
  * Декремент (уменьшение на 1) --


Примеры:

Java
int x = 3;
short y = 100;
x++; // после выполнения x становится равным 4.
y--; // после выполнения y становится равным 99.

    Префиксные унарные операции ставятся перед операндом:
 
+    Унарный плюс (обозначает положительные числа, хотя числа положительными будут и без него)
-    Унарный минус (обозначает отрицательные числа)
!    Логическое НЕ (инвертирует значение логического типа, превращая true  в false и наоборот)
++ Префиксный инкремент (увеличивает значение на 1)
--   Префиксный декремент (уменьшает значение на 1)


Примеры:

Java
int x1 = +10; // положительная десятка
int x2 = -x1; // -10

boolean b1 = true
boolean b2 = !b1; // false

++x1; // теперь x1 равен 11.
--x2; // теперь x2 равен -11


Отличие постфиксного и префиксного инкремента и декремента


   С виду может показаться, что префиксный и постфиксные инкремент и декремент одинаковы, но это не так. Их отличие в том, что префиксный инкремент и декремент возвращают значение, которое получилось после операции увеличения и уменьшения соответственно, а постфиксный инкремент и декремент возвращают исходное значение, которое было до увеличения или
уменьшения.

Пример:

Main.java
Java
class Main {
    public static void main(String[] args) {
        int x1 = 100;
        int x2 = 145;
       
        int y1 = ++x1;
        int y2 = --x2;

        // Вывод для префиксных операций
        System.out.println("\nPrefix ++, -- test");
        System.out.println("x1=" + x1 + "; y1=" + y1);
        System.out.println("x2=" + x2 + "; y2=" + y2);

        // Возвращаем исходные значения
        x1 = 100;
        x2 = 145;
  
        int z1 = x1--;
        int z2 = x2++;

        // Вывод для постфиксных операций
        System.out.println("\nPostfix ++, -- test");
        System.out.println("x1=" + x1 + "; z1=" + z1);
        System.out.println("x2=" + x2 + "; z2=" + z2);
    }
}


Этот пример выводит в консоль следующее:

Prefix ++, -- test
x1=101; y1=101
x2=144; y2=144

Postfix ++, -- test
x1=99; z1=100
x2=146; z2=145


    Как видно из примера y1 и y2 стали равны  значениям x1 и x2, которые получились после осуществления операций инкремента и декремента соответственно, а z1  и z2  стали равны значениям x1 и x2, которые были до операций инкремента и декремента.
 


Операции сравнения

   Операции сравнения позволяют проверить, больше ли один операнд другого, либо что один операнд равен другому и т. д.

Вот список операций сравнения в Java:

   = =  равенство (нужно использовать два символа равно для сравнения, а не один)
   !=  неравенство
   >  больше
   >=  больше или равно
   <  меньше
   <=  меньше или равно
 
   Данныеоперации сравнения используются для чисел, т.к. оператор == сравнивает не свойства объектов (строк), а ссылки (адреса в памяти).


   Все операции сравнения возвращают логическое значение boolean, что означает, что результат операции сравнения можно присвоить переменной этого типа и использовать в любом месте, где требуется значение типа boolean.

Пример:

class Main {
    public static void main(String[] args) {
        int x = 3;
        double d = 3.1;
        System.out.println(x == d); // false
        System.out.println(x > d);  // false
        System.out.println(x < d);  // true
    }
}

При сравнении используются следующие правила:

  * Если один из операндов NaN, то результат false.
  * -Infinity  меньше +Infinity
  * -0.0 с плавающей точкой равен +0.0 с плавающей точкой
  * При сравнении примитивов разных типов значение меньшего типа
    преобразуется в больший тип.



Логические операторы в Java
 
&      Логическое AND (И)
&&   Сокращённое AND
|        Логическое OR (ИЛИ)
||        Сокращённое OR
^       Логическое XOR (исключающее OR (ИЛИ))
!       Логическое унарное NOT (НЕ)
&=   AND с присваиванием
|=      OR с присваиванием
^=     XOR с присваиванием
==     Равно
!=      Не равно
?:       Тернарный (троичный) условный оператор
 
 
   Логические операторы &, |, ^ действуют применительно к значениям типа boolean точно так же, как и по отношению к битам целочисленных значений.
 
 
 
Логические И и ИЛИ

   Логическое И &&  и Логическое ИЛИ || ведут себя вполне ожидаемо для логического И или логического ИЛИ:

Java
boolean b1 = true && true; //true
boolean b2 = true && false; //false
boolean b3 = true || false; // true
boolean b4 = false || false; //false

System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
System.out.println(b4);


    Логическое И &&  вычисляет свой правый операнд только в том случае, если левый равен true. Если левый операнд равен false, то сразу возвращается false. Логическое ИЛИ ||  вычисляет правый операнд только в том случае, если левый равен false. Если левый операнд равен true, то сразу возвращается true. Эти два правила сокращения вычислений позволяют сразу откинуть последующие вычисления, если результат всего выражения уже известен. Это можно использовать для проверки на null  перед проверкой результата какого-либо метода объекта (будет описано в дальнейшем):

Java
if (obj != null && obj.method1()) { // obj.method1() будет вызывать только
                                    // если проверка obj!= null вернула true.
}
 
 
 
Логическое НЕ
 
   Логический оператор ! инвертирует (меняет на противоположный) булево состояние: !true == false и !false == true.



Тернарная операция

   Операция «?:» называется тернарной, потому что он принимает три операнда.

<выражение_boolean> ? <выражение1> : <выражение2>
1
   
<выражение_boolean> ? <выражение1> : <выражение2>

   Тернарная операция вычисляет <выражение_boolean>, если оно равно true, то вычисляет и возвращает <выражение1>, а если false, то <выражение2> .

Java
class Main {
    public static void main(String[] args) {
        int x = 3 > 2 ? 5 : -3; // 5
        String str1 = 3 == 2 ? "YES": "NO"; //"NO"
        System.out.println(x);
        System.out.println(str1);
    }
}
 
 
 
 
Операция instanceof

   Операция instanceof  проверяет, является ли объект экземпляром класса или экземпляром дочернего класса или экземпляром класса, реализующего интерфейс.


obj1 instanceof A

Возвращается true, если obj1  не null  и является экземпляром класса A
или экземпляром дочернего класса A  или экземпляром класса, реализующего
интерфейс A.


Object obj1 = new String("test1");
if (obj1 instanceof String) {
    System.out.println("YES");
}

Если левый операнд равен null, то результатом будет false. Код ниже
выведет “NO”:

Object obj1 = null;
if (obj1 instanceof String) {
    System.out.println("YES");
} else {
    System.out.println("NO");
}
 


Битовые (побитовые) операции

   Битовые операции в Java используются редко, но знать их нужно. Работают они также, как и в Javascript.
   Побитовые операции в Java можно проводить только над целочисленными типами данных. То есть long, int, short, char, byte. Разница в работе с целочисленными значениями только в том какой они хранят в себе диапазон допустимых значений.

Битовые операции в Java:

  <<     Битовый сдвиг влево
  <<=   Битовый сдвиг влево с присваиванием
  >>     Битовый знаковый сдвиг вправо
  >>=   Битовый знаковый сдвиг вправо с присваиванием
  >>>   Беззнаковый битовый сдвиг вправо с заполнением нулями. Он отличается от >>  тем, что ставит 0 в самую левую позицию, а >> ставит то, что было в знаковом бите
  >>>=   Беззнаковый битовый сдвиг вправо с заполнением нулями с присваиванием
  ~       Побитовый унарный оператор NOT - инвертация бит (меняет 0 на 1 и 1 на 0 во всех битах)
  &      Побитовый AND (применяет битовую операцию И)
  &=    Побитовый AND с присваиванием
  |        Побитовый OR. Применяет побитовую операцию ИЛИ
  |=      Побитовый OR с присваиванием
  ^       Побитовый исключающий OR. Применяет XOR (исключающее или)
  ^=     Побитовый исключающий OR с присваиванием

   Эти операнды работают так же, как и из аналоги в других языках программирования.

Main.java

class Main {
    public static void main(String[] args) {
        int n1 = 4; // 100 в двоичной системе
        System.out.println("n1 >> 1 = " + (n1 >> 1)); //2 или 10
                                                  // в двоичной системе.


        System.out.println("n1 << 1 = " + (n1 << 1)); ;// 8 или 100
                                                  // в двоичной системе.

        System.out.println("0b101 & 0b100 = " + (0b101 & 0b100)); // 4  (0b100)
        System.out.println("0b001 | 0b100 = " + (0b001 | 0b100)); // 5  (0b101)
        System.out.println("0b1110 ^ 0b1011 = " + (0b1110 ^ 0b1011)); //5 (0b101);

        System.out.println("-2 >> 1 = " + (-2 >> 1)); // -1 (единица со знака
                               // сдвинется вправо, так что знак не поменяется)
                                                     

        System.out.println("-2 >>> 1= " + (-2 >>> 1)); // 2147483647 (сменит
                                // знак, так как левый бит заполнится нулём).

        System.out.println("~1 = " + ~1) ;  // -2 (0b000...001
                                          // превратится в 0b1111..10)     
       
    }
}

   Результаты выполнения побитовых операций:
   Дополнительная информация по битовым операциям: ссылка

 
 
Присвоение с выполнением другой операции
    (Сокращённая запись операций))

    Сокращённые записи операций позволяют сразу выполнить операции и присвоить результат другой переменной:
 
   +=    (сложение с присвоением)
    -=    (вычитание с присвоением)
   *=    (умножение с присвоением)
    /=    (деление с присвоением)
    %=  (взятие остатка с присвоением)
    &=   (битовый И с присвоением)
    ^=    (битовое исключающее ИЛИ с присвоением)
    |=     (битовое ИЛИ с присвоением)
    <<=  (сдвиг влево с присвоением)
    >>=  (знаковый сдвиг вправо с присвоением)
    >>>=  (беззнаковый сдвиг вправо с присвоением)


   Пример: num += 7;  // это эквивалентно num = num + 7



Они работают так:

E1 compop E2
1
   
E1 compop E2
 
что эквивалентно

E1 = (T) E1 op E2;
1
   
E1 = (T) E1 op E2;

, где T  — это тип переменной E1.

То есть intx1+=x3 эквивалентно intx1=(int)x1+x2.

Main.java
Java
class Main {
    public static void main(String[] args) {
        int x1 = 100;
        byte x2 = 100;
        int x3 = 100;
       
        x1 += 300; // эквивалентно x1 = (int) x1 + 300;
        x2 += 300; // эквивалентно x2 = (byte) x2 + 300;      
        x3 += 300.1; // эквивалентно x3 = (int) x3 + 300.1;

        System.out.println("x1=" + x1);  // 400
        System.out.println("x2=" + x2);  // -112
        System.out.println("x3=" + x3);  // 400
    }
}
 
 
 

Приоритеты операций


 
   Все операции вычисляются слева направо (сначала вычисляется левый операнд, затем правый и затем сама операций, кроме операции присваивания. Операция присваивания вычисляется справа налево.

   Вычисления производятся в соответствии с таблицей приоритетов операций, приведённой ниже. Операция, находящаяся выше в таблице, имеет более высокий приоритет, чем операция, находящаяся ниже, и вычиляется раньше.
   Операции, находящиеся на одной строке, имеют одинаковый приоритет. Если в одном выражении находится несколько разных операций, то сначала вычисляется результат операции с наивысшим приоритетом. Можно использовать скобки для указания того, что сначала нужно вычислить эту
часть выражения.

Пример 1:

Java
int z = 200 * (3 + 4);


Последовательность вычисляения такая:

 1. 3+4 = 7
 2. 200 * 7 = 1 400
 3. z = 1 400

Пример 2:

Java
int x;
int y;
int z = x = y = 10000 + 20000 >> 1 + 3 * 2;


Последовательность вычисления такая:

 1. 10 000 + 20 000 = 30 000 (Присвоение вычисляется справа налево,
    поэтому сначала смотрится y=10000+20000>>1+3*2 , и вычисляется
    правая часть. В правой части ( 10000+20000>>1+3*2 ) вычисление идёт
    слева направо, и берётся 10000+20000 (выбирается среди 10000+20000 ,
    20000>>1 , 1+3  и 3*2 ), которое вычисляется перед сдвигом, так как
    у сложения приоритет выше.)
 2. 3 * 2 = 6 (В выражении 30000>>1+3*2 вычисление идёт слева направо, и
    выбирается умножение(среди 30000>>1 , 1+3  и 3*2 ), так как у него
    приоритет выше, что означает, что сложение будет выполнено раньше.)
 3. 1 + 6 = 7 (В выражении 30000>>1+6 вычисление идёт слева направо и
    сложение вычисляется раньше сдвига, так как приоритет у сложения выше.)
 4. 30 000 >> 7 = 234   (0b00…111010100110000 сдвигаем на 7 бит вправо и
    получаем 0b00…0011101010)
 5. y = 234
 6. x = 234
 7. z = 234



Таблица приоритетов операций

Группа операций     Приоритет
Группировка     |/(/ ... /)/|
Доступ к члену     |/.../ . /.../|
постфиксные     |/expr/++ /expr/--|
унарные     |++/expr/ --/expr/ +/expr/ -/expr/ ~ !|
мультипликативные     |* / %|
аддитивные     |+ -|
сдвиги     |<< >> >>>|
сравнения     |< > <= >= instanceof|
равенства     |== !=|
бинарный И     |&|
бинарный исключающее ИЛИ     |^|
бинарный ИЛИ     |||
логический И     |&&|
логический ИЛИ     ||||
тернарный     |? :|
лямбда     |->|
присваивания     |= += -= *= /= %= &= ^= |= <<= >>= >>>=|

вторник, 15 февраля 2022 г.

1.1 Java SE (Java Platform Standard Edition)

       Java SE (Java Platform Standard Edition) - стандартная редакция Java, которая используется для разработки простых Java приложений.

 

      У Oracle  есть два продукта, которые имплементируют (обеспечивают воплощение в жизнь) Java SE: Java SE Development Kit (JDK) и Java SE Runtime Environment (JRE).

 

   О том, что такое JVM, JRE, JDK, IDK и как они устроены, можно прочитать здесь: https://javaika.blogspot.com/2020/09/JVM-JRE-JDK.html

вторник, 17 ноября 2020 г.

Что такое классы в Java

    Класс представляет собой контейнер, содержащий программный код.


    (модель для создания объектов определённого типа, описывающая их структуру (набор полей и их начальное состояние) и определяющая алгоритмы (функции или методы) для работы с этими объектами)

   Код внутри класса представляет собой набор элементов - описание полей, констант, методов, интерфейсов и других классов.
   Класс - по сути является шаблоном (описанием, образцом) для объекта: он определяет, как объект будет выглядеть и какими функциями обладать.
   Класс представляется (объявляется) в исходном коде так:
   (Объявление класса состоит из заголовка (первая строка, содержащая ключевое слово class) и тела класса, заключённого между фигурными скобками {}).

   МодификаторыКласса class ИмяКласса extends КлассРодитель implements РеализуемыеИнтерфейсы
{
Тело класса
} 

   Здесь class - ключевое слово, сообщающее о том, что данная конструкция описывает класс, а не что-то другое.
   Имя класса принято начинать с большой буквы и использовать для него CamelCase.
   Имена класса и файла с Java-кодом класса с расширением .java должны совпадать,в т.ч.их регистр.

 
 
   Содержание заголовка класса

   В заголовке сначала указываются модификаторы класса, затем – ключевое слово class, затем – имя класса.
   Также класс может быть объявлен как final – в этом случае не допускается создание наследников такого класса, и на своей ветке наследования он является последним.
 
   Далее заголовок может содержать ключевое слово extends, после которого должно быть указано имя доступного не-final класса, от которого наследуется объявляемый класс.
   Если выражение extends не применяется, то класс наследуется напрямую от базового класса Object, при этом выражение extends Object допускается, но игнорируется.
   (Все классы в Java унаследованы от класса Object, который находится на вершине иерархии наследования и не является чьим-либо наследником)
   Если компилятор обнаруживает, что класс является своим наследником, то возникает ошибка компиляции. Наследование более чем от одного класса (множественное наследование) в языке Java запрещено.
 
   Далее в заголовке может быть указано ключевое слово implements, за которым должно следовать перечисление через запятую имен доступных интерфейсов, которые реализует данный класс.
   Класс может реализовывать любое количество интерфейсов.
   Если выражение implements отсутствует, то класс действительно не реализует никаких интерфейсов.

 
Содержание тела класса
 
   Тело класса, заключенное в пару фигурных скобок { }, может быть пустым или содержать описание тела класса.
 
   Тело класса может содержать объявление элементов класса (полей, методов и внутренних типов) и остальных допустимых конструкций (конструкторов, инициализаторов, статических инициализаторов).
   Класс может иметь один или несколько методов, которые должны быть объявлены внутри класса (между фигурными скобками).
 
   Элементами класса являются элементы, описанные в объявлении тела класса и переданные по наследству от класса-родителя и всех реализуемых интерфейсов при условии достаточного уровня доступа.
   Элементы класса имеют имена и передаются по наследству, областью видимости элементов является все объявление тела класса. Для элементов простые имена указываются при объявлении, составные формируются из имени класса или имени переменной объектного типа и простого имени элемента.Допускается применение к ним любого из модификаторов доступа.
   Поля и методы могут иметь одинаковые имена, поскольку обращение к полям всегда записывается без скобок, а к методам - всегда со скобками. Конструкторы, инициализаторы и статические инициализаторы не обладают именами, а потому не могут быть вызваны явно – их вызывает сама виртуальная машина. По той же причине они не обладают и модификаторами доступа
 
 

    Полное имя класса - это имя, состоящее из всех пакетов, перечисленных через точку и имени класса. Например, полное имя класса FileOutputStream из пакета java.io выглядит так:
   java.io.FileOutputStream
 
   Чтобы использовать класс в своём коде, необходимо указывать его полное имя, либо краткое (т.е. только лишь имя класса), но для этого нужно предварительно "импортировать" пакет, в котором содержится данный класс - указать его имя перед объявлением класса, со словом import.   Пример импорта пакетов:
      import java.io.FileInputStream;
      import java.io.FileOutputStream; 
      import java.io.IOException; 

   Классы из пакета java.lang импортируются по умолчанию: их указывать не обязательно.
 
   Кроме обычных переменных есть Переменные экземпляра (поля) - переменные, созданные в классе, которые будут у каждого экземпляра (объекта) класса. Они записываются через точку: maiskii.price.

  
   Объект - это экземпляр какого-либо класса, обладающий характеристиками в виде полей (fields) и поведением (функционалом) в виде методов (methods).
 
   Для создания экземпляра класса (объекта) используется оператор  new.
   Пример:
 
public class Tea {
   String name;
   int price;
 
   public static void main(String[] args) {
     Tea maiskii = new Cat();
     maiskii.price = 50;
     maiskii.name = "Assam";
  } 
}
 
 
   Все классы в Java унаследованы от класса Object.
   Класс Object, в свою очередь, имеет метод toString(), который вызывается, когда объект нужно преобразовать к строке (все объекты в Java могут быть преобразованы в строку).
   Стандартный метод toString() класса Object возвращает строку, состоящую из имени класса и адреса объекта в памяти (в шестнадцатеричном виде). Пример выводимого результата:
   “Tea is com.pack.lesson3.Tea@1fb8ee3”
 
   Однако, можно в своём классе написать свою реализацию метода toString(), и вызываться будет именно он.

   Три приведённых примера эквивалентны:

   1) Tea tea = new Tea("Assam"); System.out.println("Tea is " + tea);

   2) Tea tea = new Tea("Assam"); System.out.println("Tea is " + tea.toString());

   3) Tea tea = new Tea("Assam"); String teaText = tea.toString(); System.out.println("Tea is " + teaText);

 
 
  Абстрактные классы и методы
 
   Для абстрактных методов и классов используется модификатор abstract.
 
   Иногда бывает удобным описать только заголовок метода, без его тела, и таким образом объявить, что такой метод будет существовать в этом классе и его потомках, а реализацию этого метода (то есть его тело) описать позже в наследниках данного класса.
 
   Так как абстрактный метод не имеет тела, после описания его заголовка ставится точка с запятой.
   Так как у абстрактного метода нет тела, то к нему нельзя обращаться, пока его наследники не опишут реализацию - то есть нельзя создавать экземпляры класса, у которого есть абстрактные методы.
 
   Такой класс сам объявляется абстрактным.Класс может быть абстрактным и в случае, если у него нет абстрактных методов, но должен быть абстрактным, если такие методы есть.
   Разработчик может указать ключевое слово abstract в списке модификаторов класса, если хочет запретить создание экземпляров этого класса.
   Классы-наследники должны реализовать все абстрактные методы своего абстрактного родителя (если они есть), чтобы их можно было объявлять неабстрактными и порождать от них экземпляры.
   Конечно, классы и методы не могут быть одновременно abstract и final.
   Кроме того, абстрактный метод не может быть private, native, static.
   Сам класс может без ограничений пользоваться своими абстрактными методами, поскольку метод класса может быть вызван только у объекта, а объект при этом может быть порожден только от неабстрактного класса, который является его наследником  должен реализовать все абстрактные методы.
   По этой же причине можно объявлять переменные типа абстрактный класс. Они могут иметь значение null или ссылаться на объект, порожденный от неабстрактного наследника этого класса.
 
   О служебных словах-моификаторах доступа можно прочитать здесь: https://javaika.blogspot.com/2020/09/public-private-protected-access.html

Ключевое слово final

   Ключевое слово final (завершённый) может использоваться при объявлении классов, методов, переменных (в том числе аргументов методов).

 

   Для класса это означает, что класс не сможет иметь подклассов, т.е. запрещено наследование класса. (не допускается создание наследников такого класса, и на своей ветке наследования он является последним)

   (такой класс не является предком какого-либо класса).

 

   Попытка расширить final-класс приведёт к ошибке компиляции.

   Объявление класса завершенным неявно делает завершенными и все его методы.

   Это полезно при создании immutable (неизменяемых) объектов, например, класс String объявлен, как final.

   Следует также отметить, что к абстрактным классам (с ключевым словом abstract), нельзя применить модификатор final, т.к. это взаимоисключающие понятия.

(Одновременное объявление класса как abstract и final недопустимо).

 

   Поле (переменная класса) также может быть объявлено final, что означает, что оно инициализируется ровно один раз, и больше не будет менять своего значения.

   Статические поля класса также могут быть объявлены как final, что означает, что они должны быть проинициализированы строго один раз, и затем уже больше не менять своего значения.

 

   Локальный класс (класс, объявленный в блоке операторов между фигурными скобками, например, в теле метода, цикла или оператора ветвления) имеет доступ к членам класса, в котором он объявлен, а также к локальным переменным, объявленным как final.

   Локальные классы, как и внутренние, не могут содержать статические методы и статические поля, не объявленные как final, и могут обращаться только к статическим полям внешнего класса.


   Для интерфейса все поля интерфейса должны быть public static final, поэтому эти модификаторы указывать необязательно и даже нежелательно, чтобы не загромождать код.

   (К полям интерфейса по умолчанию применяются модификаторы public static final).

 

   Для метода final означает, что такой метод не может быть переопределен в подклассах (в наследниках) (устанавливается чтобы запретить переопределение метода в классах наследниках).

   (он не может быть переопределён потомками данного класса) 


   Это полезно, когда необходимо, чтобы исходную реализацию нельзя было переопределить.

   Если класс А содержит завершенный метод, который не может быть переопределен в классе наследнике Б, то при попытке возникнет ошибка компиляции.

 

    Можно считать, что все методы final-класса, а также все private-методы любого класса являются final:

   Не имеет смысла объявлять метод private как final, так как private метод не виден в наследниках, соответственно не может быть переопределен.

 

   Также конструктор не может быть объявлен как final.

   Для каждого аргумента метода можно указать ключевое слово final перед указанием его типа - в этом случае такой параметр не может менять своего значения в теле метода.

    Статические методы могут быть объявлены как final, что означает, что их нельзя переопределять в классах-наследниках.

 

   Для объекта (например, массива) final означает, что после присвоения ссылки на объект, уже нельзя ее изменить, но можно изменять состояние объекта.

 

   Для переменной объявление её final позволяет предотвратить изменение содержимого переменной, сделав ее, по существу, константой.

   Ключевое слово final указывают перед типом переменной, которую в этом случае необходимо сразу проинициализировать и впоследствии никогда не менять ее значение. Если попытаться изменить значение final-переменной, это приведет к ошибке компиляции. Таким образом, final-переменные становятся чем-то вроде констант, но, на самом деле, некоторые инициализаторы могут вычисляться только во время исполнения программы.

   final переменная класса, объявленная как не static, должна инициализироваться при объявлении или в теле конструктора или блоке инициализации, иначе произойдет ошибка компиляции.

   final переменные, объявленные как static, должны быть проинициализированы при объявлении или в блоке инициализации, также объявленном как static. В противном случае, опять получится ошибка компиляции. 

   Кроме переменных, объявленными как final могут быть параметры метода и локальные переменные. 

   Константы Java Константы – это переменные, значение которых не меняется. Константами в Java принято называть public static final переменные класса. Имена констант принято задавать только заглавными буквами, а слова в имени разделять знаком подчеркивания: NAME_SURNAME. 

   Преимущества от введения констант: если необходимо изменить значение константы, то это можно сделать в одном месте, также имя константы непосредственно объясняет значение хранимых данных.

 

   Существует понятие - effectively final. Применяется оно только к переменным (в том числе аргументам методов). Суть в том, что не смотря на явное отсутствие ключевого слова final, значение переменной не изменяется после инициализации. Другими словами, к такой переменной можно подставить слово final без ошибки компиляции.

  effectively final переменные могут быть использованы внутри локальных классов (Local Inner Classes), анонимных классов (Anonymous Inner Classes), стримах (Stream API).

Что такое пакеты и подпакеты в Java

    Когда файлов с классами много, то их, как правило, группируют (помещают) в специальные контейнеры - пакеты, создавая тем самым иерархическую систему  (как аналог папок (директорий) в файловой системе (на компьютере)).

 
   На диске пакет является каталогом (папкой) и все исходные файлы и файлы классов, принадлежащих одному и тому же пакету, находятся в одном каталоге.
   Java пакеты могут содержаться в сжатом виде в JAR файлах.
 
   Имена пакетов и подпакетов нужно указывать в коде класса, и они должны совпадать с именами папок и подпапок на диске. Т.е. имя класса обязано совпадать с именем файла, в котором этот класс описан, а имя пакета должно совпадать с именем папки, в которой хранится класс.


   Обычно в пакеты объединяют классы одной и той же категории, либо предоставляющие сходную функциональность.
  Таким образом можно группировать типы, что необходимо сразу для нескольких целей:
 
   - Существует специальный уровень доступа, позволяющий типам из одного пакета более тесно взаимодействовать друг с другом, чем с классами из других пакетов
 
   -    Организация классов в виде пакетов позволяет избежать конфликта имен между классами (когда разработчики называют свои классы одинаковыми именами).
      Каждый пакет имеет свое пространство имен, что позволяет создавать одноименные классы в различных пакетах.
 
   - С применением пакетов гораздо проще эффективно организовать взаимодействие подсистем друг с другом



 
   Имена вложенных пакетов (подпакетов)описываются через точку.

   То есть для класса Tea, который лежит в пакете “drinks.hot” это значит, что в папке на диске, например, cods, где хранятся все файлы проекта, должна быть папка drinks, а в ней вложенная папка hot, в которой и должен храниться файл Tea.java, в котором и содержится код класса Tea.

   package drinks.hot;
   import java.io.IOExсeption;
   public class Tea
{
  public static void main(String[] args) throws IOExсeption
{
System.out.println("TEXT");
}
}
 
   По умолчанию java уже имеет ряд встроенных пакетов, например:
 
   java.lang - базовая функциональность языка и основные типы
      (данный класс заранее импортируется по умолчанию и его импортировать вручную не нужно)
   java.util - коллекция классов структур данных
   java.io - операции ввода-вывода
   java.math - математические операции
   java.nio - новый фреймворк для ввода-вывода
   java.net - операции с сетями, сокетами, DNS-запросами
   java.security - генерация ключей, шифрование и дешифрование
   java.sql — Java Database Connectivity (JDBC) для доступа к базам данных
   java.awt — иерархия основных пакетов для родных компонентов GUI
   javax.swing — иерархия пакетов для платформенно-независимых GUI компонентов
 
 

 


Как объявляются пакеты

   Объявление пакета – это первое выражение в модуле компиляции (первой строкой после комментариев перед кодом (при их наличии))

   Объявление пакета записывается с помощью ключевого слова package, после которого указывается полное имя пакета.

   Пример:

      Для файла java/lang/Object.java

      объявлением пакета будет являться строка package java.lang;

      (Даннная строка служит одновременно объявлением пакета lang, вложенного в пакет java, и указанием,что объявляемый ниже класс Object, находится в этом пакете).

      Полное имя класса Object в этом случае будет java.lang.Object.

 

Что такое безымянные пакеты

   Если это выражение (объявление пакета) отсутствует, то такой модуль компиляции будет принадлежать безымянному пакету.

   Этот пакет по умолчанию обязательно должен поддерживаться реализацией Java-платформы.

   Безымянный пакет не может иметь вложенных пакетов, так как составное имя пакета должно обязательно начинаться с имени пакета верхнего уровня.

   (Пакет по умолчанию был введен в Java для облегчения написания небольших или временных приложений)

 

Область видимости пакетов и импорт классов пакетов (import)

   Область видимости объявления типа – пакет, в котором он располагается.

   То есть внутри этого пакета допускается обращение к типу по его простому имени.

   Из всех других пакетов необходимо обращаться по составному имени (полное имя пакета плюс простое имя типа, разделенные точкой).

 

   Так как пакеты могут иметь довольно длинные имена, для упрощения разработки ввели import-выражения:

   import-выражения позволяют импортировать типы в модуль компиляции и далее обращаться к ним по простым именам.

 

   Существует два вида import-выражений:

      1) импорт одного типа - записываются с помощью ключевого слова import и полного имени типа/

         Пример: import java.net.URL;

          Такое выражение означает, что в дальнейшем в этом модуле компиляции простое имя URL будет обозначать одноименный класс из пакета java.net

 

      2) импорт пакета - включает в себя полное имя пакета

         Пример: import java.awt.*;

         Это выражение делает доступными все типы, находящиеся в пакете java.awt, по их простому имени.

вторник, 29 сентября 2020 г.

Ключевые слова Void и Static

    Методы могут возвращать или не возвращать значения.

    Тип возвращаемых данных указывают при объявлении метода - перед его именем.


Void

    Ключевое слово (модификатор) void (пустой) означает, что метод не возвращает никаких данных (значений) в переменные как результат своей работы, а просто, к примеру, выводит на экран строку.
   Если метод возвращает какие-то данные, то вместо void нужно указать возвращаемый тип (например int), а в теле метода используется хотя бы один оператор return вида:
return выражение/переменная
    где выражение/переменная - это возвращаемое значение.


    Этот оператор возвращает переменную или результат вычисления выражения в точку вызова метода. Тип выражения должен совпадать с типом возвращаемого значения.
    Нередко возникает потребность в методах, которые возвращают значение того или иного типа: например, int для целых значений, (к примеру, если метод должен найти большее из двух целых чисел) float - для вещественных или имя класса для типов данных, определенных программистом.
   Однако, можно использовать return просто для выхода из метода: если стоит модификатор void, то выход из метода выполняется либо после выполнения последнего оператора тела метода, либо в результате выполнения оператора return; (таких операторов в теле метода может быть несколько).


Static

   Ключевое слово (модификатор) static в Java используется для управления памятью.
 
   Обозначенные ключевым словом static переменные принадлежат всему классу, а не конкретному объекту класса.
   Когда член класса объявлен как static (статический), он доступен до создания каких-либо объектов его класса и без ссылки на какой-либо объект.
 
   (В некоторых случаях нужно определить член класса, который будет использоваться независимо от любого объекта этого класса. Обычно обращение к члену класса должно выполняться только в сочетании с объектом его класса, однако можно создать член класса, который может использоваться самостоятельно, без ссылки на конкретный экземпляр: чтобы создать такой член, в начало его объявления нужно поместить ключевое слово static.)
 
 
   Статическими (объявленными с помощью ключевого слова (модификатора) static) могут быть: 
 
   (Ключевое слово static может использоваться при описании полей и методов класса)
 
 
   а) переменная класса  (поле класса)
 
   Статическая переменная может использоваться для обозначения общего свойства всех объектов, которое не является уникальным для каждого объекта.
    Статическое свойство Java является общим для всех объектов. Переменные экземпляров, объявленные как static, по существу являются глобальными переменными.
   При объявлении объектов их класса программа не создает никаких копий переменной static. Вместо этого все экземпляры класса совместно используют одну и ту же статическую переменную. Например название компании, колледжа и т. д. Статическая переменная задействует память только один раз во время загрузки класса: если какой-либо объект изменяет значение статической переменной, она сохраняет свое значение.
 
 
   б) метод класса
 
   Если ключевое слово static применяется в объявлении метода, то это статический метод Java.
 
• Статический метод относится к классу, а не к объекту класса
• Статический метод можно вызывать без создания экземпляра класса
   (обычный метод класса вызывается у экземпляра класса, а статический – у самого класса)
   (Если не использовать ключевое слово static и сделать метод нестатичным, необходимо создать объект класса для его вызова.)
 
• Статический метод может получать доступ к статическому члену и изменять его значение
• Методы, в объявлении которых использовано ключевое слово static, могут непосредственно работать только с локальными и статическими переменными.
• Они могут вызывать только другие статические методы.
• Они не могут ссылаться на члены типа this или super.
• Основной main метод Java является статическим, постольку, поскольку объект не является обязательным для вызова статического метода, если он был не статическим. Этот метод объявляют как static, поскольку он должен быть объявлен до создания любых объектов.
    Виртуальная машина сначала вызывает Java public static void main(), что приводит к выделению дополнительной памяти.
 
   в) блок
   Если для инициализации переменных типа static нужно выполнить вычисления, можно объявить статический блок, который будет выполняться только один раз при первой загрузке класса.
• Применяется для инициализации статического члена
• Выполняется перед методом main во время загрузки класса - внутренний класс

 
Не статические методы:

    Не статические методы в Java используются чаще, чем статические методы.
   Статические методы принадлежат всему классу, а не статические методы могут принадлежать любому объекту, экземпляру класса, а не всему классу. Такие методы можно вызвать только на конкретных созданных объектах.
   Не статические методы могут получать доступ и изменять поля объекта.

вторник, 8 сентября 2020 г.

Управление исключениями (возникающими ошибками) в Java

  Исключение в программировании - это возникновение ошибок и непредвиденных ситуаций при выполнении программы.

  Исключения (ошибки при выполнении программы) могут возникать в результате:

   - неправильных действий пользователя

   - отсутствии необходимого ресурса на диске

   - потери соединения с сервером по сети

   - ошибки программирования

   - неправильное использование API.

 

   Настраивают управление исключениями для того, чтобы программа чётко знала, как поступать в ситуации появления ошибок при выполнении программы.

   (чтобы предупредить и решить исключительные ситуации в программе, для того чтобы её выполнение могло быть продолжено)

   В частности, механизм исключений позволяет защитить написанный код (программный интерфейс) от неправильного использования пользователем за счет валидации (проверки) входящих данных. 

  Использование исключений в Java позволяет повысить отказоустойчивость программы за счет использования «запасных» путей, отделить логику основного кода от кода обработки исключительных ситуаций за счет использования блоков catch, а также дает возможность переложить обработку исключений на пользователя нашего кода с помощью throws.

 

   Обработка исключений в Java основана на использовании в программе следующих ключевых слов

 

try, catch, finally, throws

 

   1) try – определяет (заключает под собой) блок кода, в котором может произойти исключение;

   2) catch – определяет (заключает под собой) блок кода, в котором происходит обработка исключения;

   (Действия при сбое, который может случиться внутри оператора try)

   3) finally – определяет (заключает под собой) блок кода, который является необязательным, но при его наличии выполняется в любом случае независимо от результатов выполнения блока try.

(Блок finally часто используется для того, чтобы закрыть открытые в блоке try потоки или освободить ресурсы. Однако при написании программы не всегда возможно уследить за закрытием всех ресурсов. Для облегчения этой задачи существует конструкция try-with-resources, которая автоматически закрывает ресурсы, открытые в блоке try).

   Эти ключевые слова используются для создания в программном коде специальных обрабатывающих конструкций: try{}catch, try{}catch{}finally, try{}finally{}.

   На стадии разработки программы мы «ограждаем» опасные участки кода в отношении исключений с помощью блока try{}, предусматриваем «запасные» пути с помощью блока catch{}, в блоке finally{} мы пишем код, который выполняется в программе при любом исходе.

 

   При появлении исключения в блоке try обработчик исключения ищется в следующем за ним блоке catch. Если в catch есть обработчик данного типа исключения – управление переходит к нему. Если нет, то JVM ищет обработчик этого типа исключения в цепочке вызовов методов до тех пор, пока не будет найден подходящий catch. После выполнения блока catch управление передается в необязательный блок finally. В случае, если подходящий блок catch не найден, JVM останавливает выполнение программы, и выводит стек вызовов методов – stack trace, выполнив перед этим код блока finally при его наличии.

   Переменные, определенные в try не могут быть использованы в catch или finally, этот код не скомпилируется. Причина в том, что неизвестно, где именно в блоке try могло быть вызвано исключение, например, возможно, что исключение было вызвано до того, как был объявлен объект.


  4) throw – используется для возбуждения исключения

  5) throws – Это ключевое слово в сигнатуре метода означает, что при определенных условиях метод, может выбросить исключение

    (Ключевое слово throws используется когда не планируется обрабатывать исключение в своем методе, но необходимо предупредить пользователей метода о возможных исключительных ситуациях)

   Такое предупреждение является частью интерфейса метода и предоставляет право пользователю на собственный вариант реализации обработчика исключения (предоставляя написание кода по обработке исключения в Java пользователю метода.).

   После throws указывается тип выбрасываемого исключения.

 

   Типы выбрасываемых исключений:

   Обычно это наследники класса Exception Java.

   Поскольку Java является объектно-ориентированным языком, все исключения в Java представляют собой объекты.

   При возникновении ошибки в процессе выполнения программы исполняющая среда JVM создает объект нужного типа из иерархии исключений Java.

   Иерархия исключений java:




   Throwable - название класса "предка", от которого унаследовано множество возможных исключительных ситуаций.

   Далее всё это множество исключительных ситуаций можно разделить на две группы:

   1) Непроверяемые на стадии компиляции (неконтролируемые) (unchecked)

   Это Error (исключения, унаследованные из класса Error) + RuntimeException (часть исключений - наследников класса Exception)

  RuntimeException – исключения, генерируемые JVM во время выполнения программы. Часто причиной возникновения их являются ошибки программирования.

   К этой группе относятся ситуации, при которых восстановление дальнейшей нормальной работы программы невозможно.

   Это ошибки, возникающие при выполнении программы в результате сбоя работы JVM, переполнения памяти или сбоя системы. Обычно они свидетельствуют о серьезных проблемах, устранить которые программными средствами невозможно, такими как деление на 0, нулевой указатель и т.п.  

 

Список непроверяемых исключений:

   ArithmeticException - арифметическая ошибка, например, деление на ноль

   ArrayIndexOutOfBoundsException - выход индекса за границу массива

   ArrayStoreException - присваивание элементу массива объекта несовместимого типа

   ClassCastException - неверное приведение

   EnumConstantNotPresentException - попытка использования неопределённого значения перечисления

   IllegalArgumentException - неверный аргумент при вызове метода

   IllegalMonitorStateException - неверная операция мониторинга

   IllegalStateException - некорректное состояние приложения

   IllegalThreadStateException - запрашиваемая операция несовместима с текущим потоком

   IndexOutofBoundsException - тип индекса вышел за допустимые пределы

   NegativeArraySizeException - создан массив отрицательного размера

   NullPointerException - неверное использование пустой ссылки

NullPointerException (оно же NPE)  - это исключение, которое выбрасывается каждый раз, когда вы обращаетесь к методу или полю объекта по ссылке, которая равна null.

   NumberFormatException - неверное преобразование строки в числовой формат SecurityException - попытка нарушения безопасности

   StringIndexOutOfBounds - попытка использования индекса за пределами строки

   TypeNotPresentException - тип не найден

   UnsupportedOperationException - обнаружена неподдерживаемая операция

 

 

   2) Проверяемые на стадии компиляции (предвидимые еще на стадии написания программы) (контролируемые) (checked)

   Это Exception (кроме RuntimeException)

   Основная часть работы разработчика на Java при работе с исключениями – обработка таких ситуаций: проверяемые исключения должны быть явно пойманы в теле метода или объявлены в секции throws метода.

   Для проверяемых исключений ожидается, что другие разработчики, использующие API, будут знать, как обращаться с исключениями.


   Список проверяемых системных исключений, которые можно включать в список throws:

   ClassNotFoundException - класс не найден

   CloneNotSupportedException - попытка клонировать объект, который не реализует интерфейс Cloneable

   IllegalAccessException - запрещен доступ к классу

   InstantiationException - попытка создать объект абстрактного класса или интерфейса

   InterruptedException - поток прерван другим потоком

   NoSuchFieldException - запрашиваемое поле не существует

   NoSuchMethodException - запрашиваемый метод не существует

   ReflectiveOperationException - исключение, связанное с рефлексией

 

   Пример использования ключевых слов в java-программе:

//метод считывает строку с клавиатуры

public String input() throws MyException {//предупреждаем с помощью throws,
// что метод может выбросить исключение MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
//в блок try заключаем код, в котором может произойти исключение, в данном
// случае компилятор нам подсказывает, что метод readLine() класса
// BufferedReader может выбросить исключение ввода/вывода
    try {
        s = reader.readLine();
// в блок  catch заключаем код по обработке исключения IOException
    } catch (IOException e) {
        System.out.println(e.getMessage());
// в блоке finally закрываем поток чтения
    } finally {
// при закрытии потока тоже возможно исключение, например, если он не был открыт, поэтому “оборачиваем” код в блок try
        try {
            reader.close();
// пишем обработку исключения при закрытии потока чтения
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// мы решили, что пустая строка может нарушить в дальнейшем работу нашей программы, например, на результате этого метода нам надо вызывать метод substring(1,2), поэтому мы вынуждены прервать выполнение программы с генерацией своего типа исключения MyException с помощью throw
        throw new MyException("String can not be empty!");
    }
    return s;
}
 

 Этот же пример с помощью try-with-resources:

public String input() throws MyException {
    String s = null;
    try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")){
        throw new MyException ("String can not be empty!");
    }
    return s;
}

Наследование в Java

   «родительское/дочернее»     Наследование (inheritance) - свойство системы, позволяющее описать (создать) новый класс на основе уже су...