Инструменты пользователя

Инструменты сайта


develop:java:in

Это старая версия документа!


Begin

ООП

В отличии от процедурных типов, в ООП на первом месте стоят данные, а уже после алгоритмы для их обработки

:!: Notes

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

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

Объекты и объектные переменные не одно и тоже. Объект всегда сам по себе, переменные это лишь ссылки на него, присвоив такую переменную другой переменной, обе они будут ссылаться на один и тот же объект
Без инициализации, объектная переменная ничего не содержит и с-но нельзя вызывать никакие методы
Объекты можно свободно использовать напрямую, без ссылок (типа «var d = new Date().toString()»), но тогда только единожды, сборщик мусора чистит все потом автоматом
Операция new так же возвращает ссылку на объект, хранящийся в другом месте

Все объекты хранятся в динамической памяти, у переменных проводится параллель с ссылками в C++

Существует 3 типа отношений между классами:

  • Зависимость (методы одного выполняют какие либо д-я другого)
  • Агрегирование (содержит другие объекты, точнее ссылки на них)
  • Наследование

Date

Есть два класса с разным назначением
«Date()» представляет момент времени, для расчета/подсчета, в мс
«LocalDate()» создан для представления даты/времени в нужном формате и т.д., он содержит такие методы как getYear/Month() и т.д.

:!: Notes

Некоторые методы, в т.ч. «Date().plusDays() или String().toUpperCase()», не модифицируют исхрдный объект а возвращают новый

Классы

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

:!: Notes

Каждый класс может содержаться в отдельном файле, может и несколько быть в одном, обычно раздельно
Утилита «javac» компилирует указанный файл. Если есть связи, она автоматически скомпилирует связанные файлы, и обновит при необходимости, работает аналогично утилите «make» в линукс
В каждом файле должен быть один класс с модификатором «public» и методом «main()», как точкой входа в программу
Конструкторы вызываются только с оператором «new», всегда
Неявный аргумент «this» так же присутствует во всех методах, смысл остается прежним

:!: NullPointerExceptionNotes

Распространенная мозоль, возникает если обратится к методу объекта который содержит «null» вместо ссылки на объект
Есть пару спец методов, например Objects.requireNonNullElse(var, «Default value») или Objects.requireNonNull(var, «Исключение с данным сообщением»)

:!: Notes

«final» константа, указывает на то что поле не изменяемое в этом классе, константы можно делать открытыми, принцип инкапсуляции не нарушается
«static» статическое поле, т.е. поле класса а не объекта, существует в единственном экземпляре, всегда и доступно всем объектам класса
Есть понятие «блок инициализации», в описании класса, блок без заголовка, в нем можно инициализировать свойства создаваемого объекта, выполняется перед конструктором
Есть и статический блок инициализации, для статических полей с-но

:!: Пакеты. Notes

Повторяют структуру файловой системы, классы распределены по папкам, обращаясь к таким классам, нужно указывать полный путь

Параметры методов

:!: Notes

Используется только вызов по значению т.е. в ф-ю всегда передается только копия переменной
Но это не относится к объектам т.к. в переменных находятся только ссылки на них, да, передается копия переменной, но ссылается она на тот же самый объект в памяти, поэтому переданный объект можно изменить внутри метода

Рекомендации

:!: Notes

Всегда храните данные в переменных объявленных как private
Следует всеми способами избегать нарушения инкапсуляции

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

Не употребляйте в классе слишком много простых типов
Связанные между собой данные объединяйте в классы

Не для всех полей нужно создавать методы доступа и модификации
Существуют поля которые не требуют изменения после создания объекта

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

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

Отдавайте предпочтения неизменяемым классам
Не изменяемые классы, которые возвращают копию значения а не измененный результат, в случае приемлемости конечно же, более безопасны для много-поточного выполнения

Классы, суперклассы и подклассы

:!: Наследование. Notes

Подклассы не имеют доступа к закрытым полям базового класса!
Для обращения к методам базового класса есть ключевое слово «super», т.е. по сути у классов сохраняется интерфейс даже при наследовании
Еще наследование существует только одного типа, открытого

Модификатором «final» можно определить класс конечным т.е. го наследование становится запрещено, при указании модификатора, его методы автоматически становятся тоже конечными, но не поля

Рекомендации:
Размещайте общие поля и операции в супер-классе

Старайтесь не пользоваться защищенными полями
Лучше пресекать возможность нарушения инкапсуляции

Используйте наследование для моделирования отношений «является»
Если подкласс по смыслу «не является» базовым, то наследование не оправдано, внесет только больше путаницы и проблем

Не применяйте наследование если не все методы имеет смысл наследовать

Переопределяя метод, не изменяйте его предполагаемое поведение

Пользуйтесь принципом полиморфизма а не проверкой типов
Вместо ветвления в зависимости от типа, если у методов есть общий характер, можно вынести их в общий супер класс и вызывать спокойно из обоих объектов

:!: Полиморфизм. Notes

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

т.е. объект подкласса можно присвоить базовому типу, можно даже самому супер-пупер классу «Object», который базовый всея объектов, но методы использовать можно только того класса, которым он в данный момент является, если мы точно знаем его настоящий подкласс, тогда приводим к нему и вызываем его метод, приведение как обычных типов, в скобках
В случае ошибки хз хотя наверно пустыми значениями инициализируется

:!: Абстрактные классы. Notes

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

Если класс содержит абстрактные методы то уже является абстрактным, модификатор «abstract» у класса можно указывать можно нет, можно указать даже если нет абстрактных методов, подклассы тоже будут абстрактными (непонятка, в книге сказано что «не перестанет быть абстрактным даже если определить все методы», как тогда создаются объекты ? оО хня какая-то)

Собсна объекты не создаются у абстрактных классов

:!: Еще раз про доступы. Модификаторы могут быть следующими:

  • private - ограничивает пределами класса
  • public - не ограничивает
  • protected - пределами класса и всеми подклассами
  • не указан - по умолчанию пределы пакета
:!: Списочный массив. ArrayList

Массив динамической длинны, для хранения объектов, объявляется одним из следующих образов:

ArrayList<ClassName> myVar = new ArrayList<ClassName>();
ArrayList<ClassName> myVar = new ArrayList<>();
var myVar = new ArrayList<ClassName>();
var myVar = new ArrayList<>();

Облегчает объявление после компиляции, но изменение размера после объявления все так же проблемная операция

Для упрощения можно задать размер сразу или позже, ф-ей «ensureCapacity()», по аналогии с векторами С++. По умолчанию он и так есть, какой то, просто при заполнении автоматически увеличивается на какую то величину
Использование этого размера здесь, не тоже самое что размеры в обычных массивах, там память зарезервирована а здесь это просто метка того какого размера может быть список, памяти он не занимает
«trimToSize()» еще тоже есть для обрезки

Доступ к элементам через ф-ии «get/set», добавление новых элементов только через add(), set() можно использовать только для замены уже имеющегося элемента, иначе ошибка будет

Интерфейсы, лямбда-выражения, внутренние классы

:!: Интерфейсы. Notes

Интерфейс классом не является, это скорее соглашение о том что именно должен делать класс, но не как это делать
Может содержать описание методов, как и сами (простые) методы, не содержит полей

Для указания того что класс реализует интерфейс существует ключевое слово «implements»
С-но этот класс должен реализовывать все методы перечисленные в классе

В интерфейсе можно объявлять константы
Объекты интерфейса создавать нельзя, но можно объявить переменную интерфейса, при этом она должна ссылаться на класс реализующий эту переменную. Например операция InstanceOf покажет реализует ли класс указанный интерфейс

Интерфейсы так же могут образовывать иерархию наследования
В отличии от наследования классов, где нет множественного наследования, реализовывать можно несколько интерфейсов в одном классе

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

:!: Клонирование. Notes

С клонированием в java немного треш, у класса object есть метод «clone()», но он делает только неполное клонирование т.е. подобъекты (объекты внутри объекта) все еще остаются теми же самыми. Для полного клонирования нужно переопределять этот метод, определять интерфейс «Cloneable» и учитывать кучу деталей

:!: Лямбда выражения Notes

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

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

Лямбда-выражения имеют следующую структуру:

  • Блок кода
  • Параметры
  • и значения свободных переменных (т.е. переменных которые не являются параметрами и не определены в кода)

т.е. в выражении можно использовать переменные которые объявлены за его пределами, но эти переменные должны быть не изменяемыми и собсна не меняться в самом выражении

Собственные
Лямбда выражения применяются именно для отложенного выполнения, например в потоке или неоднократное выполнение или по какому-нибудь событию и т.д.
Пример реализации в собственном методе:

# вызов
repeat(10, () -> System.out.println("Hello, world"));
 
# реализация
public static void repeat()int n, Runnable action){
  for(int i = 0; i < n; i++) action.run();
}

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

:!: Ссылки в лямбда-выражениях

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

Ссылки на методы. Разновидности:

  • x → System.out.println(x) - Объект::МетодЭкземпляра
  • (x,y) → x.compareToIgnoreCase(y) - Класс::МетодЭкземпляра
  • (x,y) → Math.pow(x,y) - Объект::СтатическийМетод

Еще примеры:

  • separator::equals - x → separator.equals(x) - задан объект и метод экземпляра
  • String::trim - x → x.trim() - задан класс и метод экземпляра
  • String::concat - (x,y) → x.concat(y) - тоже метод экземпляра но уже с явным параметром
  • IntegerValueOf - x → Integer::valueOf(x) - статический метод
  • Integer[]::new - n → new Integer[n] - Ссылка на конструктор массива

Но ссылку на метод можно применить только в том случае, если в его теле вызывается единственный метод и больше ничего не делается. Например это не подойдет, т.к. есть еще и сравнение «s → s.length() == 0»

Ссылки на конструкторы. Все тоже самое, только имя метод передается как «new»
Если несколько конструкторов, выбирается исходя из контекста
Эти ссылки помогают обойти ограничение java в том что нельзя создать массив обобщенного типа, при попытке будет перезаписываться тип или что то такое
Но такую ссылку можно передать в метод типа «toArray()», тогда все чики-пики, например «Person[] pople = stream.toArray(Person[]::new)«

Исключения, утверждения и протоколирование

:!: Обработка ошибок

В случае возникновения исключения, следует стремится к одному из двух состояний:

  • Вернуться в безопасное состояние и разрешить пользователю выполнить другие команды
  • Дать пользователю возможность сохранить результаты своей работы и аккуратно завершить работу

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

Иерархия Error описывает внутренние ошибки и ситуации в связи с нехваткой ресурсов в исполняющей системе Java. Эти объекты нельзя сгенерировать самостоятельно. Считаются Непроверяемыми

Исключения типа RuntimeException возникают в следствии ошибок программирования:

  • неверное приведение типов
  • выход за пределы массива
  • обращение к объекту по пустой ссылке «null»

Остальные в случае непредвиденного стечения обстоятельств:

  • попытка чтения при достижении конца файла
  • попытка открыть несуществующий файл

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

public FileInputStream(String name) throws FileNotFoundException

Но не стоит перечислять все возможные исключения, как минимум, точно стоит указать те что вызываются вручную, методом «throw»
Классы исключения такие же классы, можно объявить базовый класс и допустимо будет сгенерировать его подкласс. Наследуя, можно объявлять свои классы

:!: Генерация исключений

После генерации исключения, управление в эту часть программы больше не вернется, перейдет туда где оно перехватится, получается

String readData(Scanner in) throw EOFException{
  ...
  while(...){
    if(!in.hasNext()){
      throw new EOFException();
      # throw new EOFException("Добавить текст описания");
    }
  }
}
:!:
 
develop/java/in.1674055859.txt.gz · Последнее изменение: 2023/01/18 15:30 — admin