воскресенье, 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

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

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