вторник, 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, по их простому имени.

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

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