Что будет если единственный конструктор класса объявлен как final

Обновлено: 01.05.2024

"Можно ли получить доступ к private переменным класса и если да, то каким образом?"
"Модификаторы. Назначение и варианты использования."
"Что такое volatile и transient?"
"Контексты использования модификаторов (класс/поле/метод)."
"Какой из модификаторов более строгий: protected или package-private?"
"Расширение модификаторов при наследовании, переопределение и сокрытие методов. Если у класса-родителя есть метод, объявленный как private, может ли наследник расширить его видимость? А если protected? А сузить видимость?"
"Модификатор abstract и final для классов/методов."
"Имеет ли смысл объявлять метод private final?"
"Какие особенности инициализации final переменных?"
"Что будет, если единственный конструктор класса объявлен как final?"

1. Модификаторы — ключевые слова, которые добавляются при инициализации для изменения значений. Язык Java имеет широкий спектр модификаторов, основные из них:
- модификаторы доступа;
- модификаторы класса, метода, переменной и потока, используемые не для доступа.

скрытый текст 2. В Java существуют следующие модификаторы доступа:
- private: члены класса доступны только внутри класса;
- default (package-private) (модификатор, по-умолчанию): члены класса видны внутри пакета (если класс будет так объявлен он будет доступен только внутри пакета);
- protected: члены класса доступны внутри пакета и в наследниках;
- public: члены класс доступны всем;

2.1. Последовательность модификаторов по убыванию уровня закрытости: private, default, protected, public.

2.2. Доступ к полям модификатором доступа private рекомендуется осуществлять через специальные методы с заголовками, начинающимися с get/set.

2.2.1. С помощью Java Reflection можно получить доступ к части кода, к которой мы не должны получать доступ. Например, мы можем получить доступ к закрытым полям класса и менять их значения. Это может быть серьезной угрозой безопасности.

2.3. Во время наследования возможно изменения модификаторов доступа в сторону большей видимости. Так сделано для того, чтобы не нарушался принцип LSP («подкласс не должен требовать от вызывающего кода больше, чем базовый класс, и не должен предоставлять вызывающему коду меньше, чем базовый класс») для наследуемого класса.

2.3.1. Поэтому методы, объявленные как public в суперклассе, также должны быть public во всех подклассах. Методы, объявленные как protected в суперклассе, должны либо быть либо protected, либо public в подклассах; они не могут быть private. Методы, объявленные как private для всех не наследуются, так что нет никакого правила для них.

3. Java предоставляет ряд модификаторов не для доступа, а для реализации многих других функциональных возможностей:
- модификатор static применяется для создания статических методов и переменных класса;
- модификатор final используется для завершения реализации классов, методов и переменных;
- модификатор abstract необходим для создания абстрактных классов и методов;
- модификаторы synchronized и volatile используются в Java для потоков;
- прочие модификаторы (strictfp, transient, native).

3.1. Модификатор synchronized применяется только к методам и их частям. Указывает, что метод может быть доступен только одному потоку одновременно. В Java модификатор synchronized может быть применен с любым из четырех модификаторов уровня доступа.

3.2. Модификатор transient: переменная экземпляра отмеченная как transient указывает виртуальной машине Java (JVM пропустить эту переменную при сериализации содержащего её объекта.

3.2.1. Применяется только для переменных уровня класса (локальные переменные не могут быть объявлены как transient). Transient переменные могут не быть final или static.

3.3. Модификатор volatile используется, чтобы указать JVM, что при обращении к полю не используется кэш (имеется ввиду область памяти в которой JVM может сохранять локальную копию переменной, чтобы уменьшить время обращения к переменной). Для volatile переменной JVM гарантирует синхронизацию для операций чтения/записи, но не гарантирует для операций изменения значения переменной.

3.3.1. Модификатор применим только к переменным экземпляра, которые имеют тип объект или private. Ссылка на объект с модификатором volatile может быть null.

3.3.2. Может использоваться со static переменными. Не используется с final переменными.

3.4. Модификатор strictfp применяется для методов и классов. Обеспечивает выполнение операций над числами типа float и double (с плавающей запятой) по стандарту IEEE 754.

3.5. Модификатор native используется только для методов. Обозначает, что метод написан на другом языке программирования. Классы в Java используют native методы для повышения производительности и доступа к аппаратным средствам Можно предавать и возвращать Java объекты из native методов. Сигнатура метода должна заканчиваться “;”, фигурные скобки вызовут ошибку компиляции.

4.1. Переменная с final может быть инициализирована только один раз. Они не инициализируются по умолчанию, необходимо явно присвоить значение при объявлении или в конструкторе, иначе – ошибка компиляции. Ссылочная переменная, объявленная как final, никогда не может быть назначена для обозначения другого объекта. Однако поля объекта могут быть изменены. Также это справедливо и для массивов, потому что массивы являются объектами: массив может быть изменен, но переменная всегда будет ссылаться на тот же самый массив.

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

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

4.2.1. Абстрактный класс не может создать экземпляр. Если класс объявлен как abstract, то единственная цель для него быть расширенным через наследование. Класс не может быть одновременно abstract и final, так как класс с модификатором final не может быть расширенным.

4.3. От класса с final нельзя наследоваться. Поэтому все его методы не могут быть переопределены и неявно также становятся финальными.

4.3.1. Абстрактный метод является методом, объявленным без реализации (без тела метода). Методы abstract никогда не могут быть final.

5. "Суперпункт" для разбора частных вопросов.

5.1. "Имеет ли смысл объявлять метод private final?" Модификатор final позволяет заблокировать метод от переопределения в классах наследниках. Однако private методы и так недоступны в классах наследниках, поэтому перепределить такие методы там нельзя и дополнительный модификатор final не окажет никакого влияния. Можно сказать, что private методы и так неявно являются final методами.

5.2. "Что будет, если единственный конструктор класса объявлен как final?" Конструктор не может иметь подобного модификатора.

6.1. Классы (включая любые вложенные классы) могут быть default и strictfp. За исключением анонимных они могут быть abstract или final. Вложенные за исключением локальных (включая анонимные) могут иметь модификатор доступа (верхнего уровня — только public). И только вложенные классы могут быть static.

6.2. Методы в общем случае могут использовать все модификаторы за исключением специально предназначенных для переменных transient и volatile. Конструкторы в отличие от методов не может иметь модификаторов abstract, final, native, static или synchronized.

6.3. Переменные в общем случае могут использовать все модификаторы за исключением не имеющих для них смысла abstract, native и strictfp.

6.4. Логический блок может иметь модификаторы default, static и (как часть метода) synchronized.

К списку вопросов по всем темам

Вопросы. Часть 3

43. Каким образом можно обратиться к локальной переменной метода из анонимного класса, объявленного в теле этого метода? Есть ли какие-нибудь ограничения для такой переменной?
44. Как связан любой пользовательский класс с классом Object?
45. Расскажите про каждый из методов класса Object.
46. Что такое метод equals(). Чем он отличается от операции ==.
47. Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода?
48. Если equals() переопределен, есть ли какие-либо другие методы, которые следует переопределить?
49. В чем особенность работы методов hashCode и equals? Каким образом реализованы методы hashCode и equals в классе Object? Какие правила и соглашения существуют для реализации этих методов? Когда они применяются?
50. Какой метод возвращает строковое представление объекта?
51. Что будет, если переопределить equals не переопределяя hashCode? Какие могут возникнуть проблемы?
52. Есть ли какие-либо рекомендации о том, какие поля следует использовать при подсчете hashCode?
53. Как вы думаете, будут ли какие-то проблемы, если у объекта, который используется в качестве ключа в hashMap изменится поле, которое участвует в определении hashCode?
54. Чем отличается абстрактный класс от интерфейса, в каких случаях что вы будете использовать?
55. Можно ли получить доступ к private переменным класса и если да, то каким образом?
56. Что такое volatile и transient? Для чего и в каких случаях можно было бы использовать default?
57. Расширение модификаторов при наследовании, переопределении и сокрытии методов. Если у класса-родителя есть метод, объявленный как private, может ли наследник расширить его видимость? А если protected? А сузить видимость?
58. Имеет ли смысл объявлять метод private final?
59. Какие особенности инициализации final переменных?
60. Что будет, если единственный конструктор класса объявлен как final?
61. Что такое finalize? Зачем он нужен? Что Вы можете рассказать о сборщике мусора и алгоритмах его работы.
62. Почему метод clone объявлен как protected? Что необходимо для реализации клонирования?

Ответы. Часть 3

43. Каким образом можно обратиться к локальной переменной метода из анонимного класса, объявленного в теле этого метода? Есть ли какие-нибудь ограничения для такой переменной?

Также как и локальные классы, анонимные могут захватывать переменные, доступ к локальным переменным происходит по тем же правилам:

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

Анонимные классы также могут содержать в себе локальные классы. Конструктора в анонимном классе быть не может.

влияние предмета наблюдения на наблюдателя посредством наблюдения

Jun 22 nd , 2013

54 вопроса на знание java core. Как-то мне пришлось на эти вопросы ответить. Надеюсь я нигде не налажал )

  • boolean equals(Object o)
  • void finalize() // вызывается сборщиком мусора, когда gc определил, что ссылок на объект больше нет.
  • Class<?> getClass() //возвращает в рантайме класс данного объекта.
  • int hashCode()
  • void notify() // просыпается одни поток, который ждет на “мониторе” данного объекта.
  • void notifyAll() // просыпаются все потоки, которые ждут на “мониторе” данного объекта.
  • String toString()
  • void wait() // Приводит данный поток в ожидание, пока другой поток не вызовит notify() или notifyAll() методы для этого объекта.
  • void wait(long timeout) // Приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() для этого метода, или пока не исчет указанный промежуток времени.
  • void wait(long timeout, int nanos) // nanos - дополнительное время в наносекундах.
  • Object clone() // create and returns a copy of this object.
  • Причем равенство должно работать в обе стороны.
  • Должно выполняться условие транзитивности.
  • Для одних и тех же экземпляров результат работы метода должен быть всегда одинаков.

Если вы хотите переопределить equals , какие условия должны удовлетворяться для переопределенного метода?

См. 2) . Так же должно выполняться условие, что возвращаемое значение работы метода hashCode() для объектов равных относительно метода equals() должен быть одинаковым.

  • Когда метод hashCode() последовательно вызывают на одном и том же объекте, метод должен возвращать в этом случае одни и теже значения, при условии, что никакая информация, которая используется в equals() при сравнении не изменилась. Возвращаемый хэш код может быть различным в различных запущенных приложениях.
  • Два объекта равные по equals() должны возвращать одинаковый hashCode() .
  • Не обязательно, что объекты не равные по equals() должны возвращать разные hashCode() .

В классе Object метод equals производит сравнение по ссылке, метод hashCode() генерироет hash при помощи нативного кода из адреса ссылки.

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

Те, которые используют при определении метода equals() . Хэш код должен быть равномерно распределен на области возможных принимаемых значений.

Как вы думаете, будут ли какие-то проблемы, если у объекта, который используется в качестве ключа в hashMap изменится поле, которое участвует в определении hashCode?

  • private ,
  • protected ,
  • package-private (default) ,
  • public .

package-private . Поле с package-private уровнем доступа будет видно только в данном пакете всем классам.Тогда как protected видно для наследников данного класса, а так же для классов находящихся в данном пакете.

Если у класса-родителя есть метод, объявленный как private , может ли наследник расширить его видимость? А если protected ? А сузить видимость?

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

  • Для класса. Класс помеченный при помощи final не может иметь наследников.
  • Для метода. Метод помеченный при помощи final не может быть переопределен в классах наследниках.
  • Для поля. Поле помеченное при помощи слова final не может изменить свое значение после инициализации (инициализируется либо при описании, либо в конструкторе/статическом блоке).
  • Значение локальных переменных, а так же параметров метода помеченных при помощи слова final не могут быть изменены после присвоения.
  • static-блок вызывается при загрузке класса, поэтому static-блок super-класса будет вызван раньше, чем static-блок наследника.
  • Вызов других конструкций следующий (при создании экземпляра): init-блок super-класса, конструктор super-класса, init-блок наследника, конструктор наследника. Т.к. init-блок всегда выполняется перед конструктором, а перед вызовом контруктора наследника всегда вызывается конструктор super-класса.
  • init / static блоки в рамках одного класса вызываются в последовательности определения.
  • К методу.
  • К внутреннему классу.
  • К полю.
  • К импортируемы классам (с 5-ой java).
  • java.lang.ExceptionInInitializerError - если исключение наследуется от RuntimeException .
  • exception , который и вызвал исключение, если он наследуется от RuntimeException .
  • java.lang.Error - если исключение вызвано Error .
  • java.lang.ThreadDeath - смерть потока. Ничего не вываливается.

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

  • Обычные классы ( Top level classes )
  • Интерфейсы ( Interfaces )
  • Перечисления ( Enum )
  • Статические вложенные классы ( Static nested classes )
    • Есть возможность обращения к внутренним статическим полям и методам класса обертки.
    • Внутренние статические интерфейсы могут содерать только статические мотоды.
    • Есть возможность обращения к внутренним полям и методам класса обертки.
    • Не может иметь статических объявлений.
    • Нельзя объявить таким образом интерфейс. А если его объявить без идентификатора static , то он автоматически будет добавлен.
    • Внутри такого класса нельзя объявить перечисления.
    • Если нужно явно получить this внешнего класса - OuterClass.this
    • Видны только в пределах блока, в котором объявлены.
    • Не могут быть объявлены как private / public / protected или static (по этой причине интерфейсы нельзя объявить локально).
    • Не могут иметь внутри себя статических объявлений (полей, методов, классов).
    • Имеют доступ к полям и методам обрамляющего класса.
    • Можно обращаться к локальным переменным и параметрам метода, если они объявлены с модификатором final .
    • Локальный класс без имени.

    Если вложенный класс не статический и поле не статическое, то можно просто обратиться к этому полю из внутреннего класса, если только у внутреннего класса не существует поля с таким же литералом, в этом случае нужно обраться через ссылку на внешний класс где-то так - OuterClass.this

    Каким образом можно обратиться к локальной переменной метода из анонимного класса, объявленного в теле этого метода? Есть ли каке-нибудь ограничения для такой переменной?


    Наследовать Thread будет верным лишь в случае создания другой имплементации потока. Для выполнения какой-нибудь задачи в отдельном потоке использование наследования будет идеологически неверным.

    • Thread.stop(); // depreceted
    • При вызове метода interrupt() , флаг прерывания устанавливается в true, после чего в потоке должен быть реализован метод его завершения (выход из метода run() ).
    • valotile - помечает объект, чтобы он не кэшировался отдельно для каждого потока. Все запросы к переменной будут направляться непосредственно в память.
    • syhcronized .

    Есть некоторый метод, который исполняет операцию i++ . Переменная i типа int . Предполагается, что код будет исполнятся в многопоточной среде. Следует ли синхронизировать блок?

    Оновременно нельзя. Т.к. методы объявлены как synchronized , то одноременно оперировать с объектом может только один поток, который получил lock объекта . Поэтому: если synchronized метод выполняется в первом потоке, чтобы выполнить какой-либо synchronized метод объекта во втором потоке, второй поток будет вынужден ждать пока станет доступен lock объекта .

    Что используется в качестве mutex, если метод объявлен static synchronized ? Можно ли создавать новые экземпляры класса, пока выполняется static synchronized метод?

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

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

    Для указание того, что при сериализации/десериализации данное поле не нужно сериализовать/десериализовывать.

    • wait() - Приводит поток в ожидание, пока другой поток не вызовит notify() или notifyAll() методы для этого объекта. При этом все эти методы должны быть вызваны в блоке synchronized.
    • notify() - просыпается одни поток, который ждет на “мониторе” данного объекта.
    • notifyAll() - просыпаются все потоки, которые ждут на “мониторе” данного объекта. Эти методы должны вызываться в блоке synchronized .
      Применяются для организации работы потоков. Используется один объект, который выполняет управляющую.
      Именно у него и вызываются эти методы.
      При вызове одного из этих методов блокировка на объект снимается.

    Какие особенности использования метода wait ? При каких условиях поток может выйти из режима ожидания?

    • Если задан параметр/параметры, определяющий время и если поток не будет разбужен в течении этого времени при помощи методов notify() или notifyAll() , тогда он будет разбужен по прошествии указанного времени.
    • Если не задан параметр/параметры, определяющие время, то поток будет разбужен только при помощи методов notify() или notifyAll() .

    Предположим в методе run возник RuntimeException , который не был пойман. Что случится с потоком? Есть ли способ узнать о том, что Exception произошел (не заключая все тело run в блок try-catch )? Есть ли способ восстановить работу потока после того как это произошло?

    checked / unchecked . Если checked исключение не отлавливается, то это приводит к ошибке на этапе компиляции. Unchecked исключение - то, которое разработчик не должен допустить, т.к. имеет для этого возможность.
    Если исключение потомок RuntimeException или Error , то это unchecked исключение. Если исключение потомок Exception (и не потомок RuntimeException ), то это checked исключение.

    Да, если возникающее исключение не checked или checked исключение будет передано дальше по иерархии, или если оно будет поймано в ещё одном блоке try .

    Предположим, есть блок try-finally . В блоке try возникло исключение и выполнение переместилось в блок finally . В блоке finally тоже возникло исключение. Какое из двух исключений “выпадет” из блока try-finally ? Что случится со вторым исключением?

    Выпадает, то есть, не передается по иерархии вызовов первое исключение. И оно просто не попадет в иерархию вызовов.

    Предположим, есть метод, который может выбросить IOException и FileNotFoundException в какой последовательности должны идти блоки catch ? Сколько блоков catch будет выполнено?

    Предположим вам необходимо создать свой собственный класс Exception . Какими мотивами вы будете руководствоваться при выборе типа исключения: checked / unchecked ?

    Если исключение возникло из-за того, что клиент нарушал контракт, то это unchecked exeption. Если же исключение возникло по какой-нибудь другой причине, то это checked exeption.

    Что такое finalize ? Зачем он нужен? Что Вы можете рассказать о сборщике мусора и алгоритмах его работы.

    Метод finalize() вызывается перед тем, как объект будет удален gc . Существует много различных реализаций gc . Основа работы следующая, gc помечает объекты на которых больше не ссылаются другие объекты для их удаления. Затем на одном из проходов помеченные объекты удаляются.
    Вызов finalize() не гарантируется, т.к. приложение может быть завершено до того, как будет запущена ещё одна сборка мусора. Да, можно отменить сборку объекта с помощью метода finalize() , присвоив его ссылку какому-то статистическому мето

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

    Вопросы и ответы по теме ООП (объектно ориентированное программирование) для собеседования по Java.

    К списку вопросов по всем темам

    Список всех вопросов по ООП

    1. Назовите принципы ООП и расскажите о каждом.
    2. Дайте определение понятию “класс”.
    3. Что такое поле/атрибут класса?
    4. Как правильно организовать доступ к полям класса?
    5. Дайте определение понятию “конструктор”.
    6. Чем отличаются конструкторы по умолчанию, копирования и конструктор с параметрами?
    7. Какие модификации уровня доступа вы знаете, расскажите про каждый из них.
    8. Расскажите об особенностях класса с единственным закрытым (private) конструктором.
    9. О чем говорят ключевые слова “this”, “super”, где и как их можно использовать?
    10. Дайте определение понятию “метод”.
    11. Что такое сигнатура метода?
    12. Какие методы называются перегруженными?
    13. Могут ли нестатические методы перегрузить статические?
    14. Расскажите про переопределение методов.
    15. Может ли метод принимать разное количество параметров (аргументы переменной длины)?
    16. Можно ли сузить уровень доступа/тип возвращаемого значения при переопределении метода?
    17. Как получить доступ к переопределенным методам родительского класса?
    18. Какие преобразования называются нисходящими и восходящими?
    19. Чем отличается переопределение от перегрузки?
    20. Где можно инициализировать статические/нестатические поля?

    21. Зачем нужен оператор instanceof?
    22. Зачем нужны и какие бывают блоки инициализации?
    23. Каков порядок вызова конструкторов и блоков инициализации двух классов: потомка и его предка?
    24. Где и для чего используется модификатор abstract?
    25. Можно ли объявить метод абстрактным и статическим одновременно?
    26. Что означает ключевое слово static?
    27. К каким конструкциям Java применим модификатор static?
    28. Что будет, если в static блоке кода возникнет исключительная ситуация?
    29. Можно ли перегрузить static метод?
    30. Что такое статический класс, какие особенности его использования?
    31. Какие особенности инициализации final static переменных?
    32. Как влияет модификатор static на класс/метод/поле?
    33. О чем говорит ключевое слово final?
    34. Дайте определение понятию “интерфейс”.
    35. Какие модификаторы по умолчанию имеют поля и методы интерфейсов?
    36. Почему нельзя объявить метод интерфейса с модификатором final или static?
    37. Какие типы классов бывают в java (вложенные… и.т.д.)
    38. Какие особенности создания вложенных классов: простых и статических.
    39. Что вы знаете о вложенных классах, зачем они используются? Классификация, варианты использования, о нарушении инкапсуляции.
    40. В чем разница вложенных и внутренних классов?
    41. Какие классы называются анонимными?
    42. Каким образом из вложенного класса получить доступ к полю внешнего класса?

    43. Каким образом можно обратиться к локальной переменной метода из анонимного класса, объявленного в теле этого метода? Есть ли какие-нибудь ограничения для такой переменной?
    44. Как связан любой пользовательский класс с классом Object?
    45. Расскажите про каждый из методов класса Object.
    46. Что такое метод equals(). Чем он отличается от операции ==.
    47. Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода?
    48. Если equals() переопределен, есть ли какие-либо другие методы, которые следует переопределить?
    49. В чем особенность работы методов hashCode и equals? Каким образом реализованы методы hashCode и equals в классе Object? Какие правила и соглашения существуют для реализации этих методов? Когда они применяются?
    50. Какой метод возвращает строковое представление объекта?
    51. Что будет, если переопределить equals не переопределяя hashCode? Какие могут возникнуть проблемы?
    52. Есть ли какие-либо рекомендации о том, какие поля следует использовать при подсчете hashCode?
    53. Как вы думаете, будут ли какие-то проблемы, если у объекта, который используется в качестве ключа в hashMap изменится поле, которое участвует в определении hashCode?
    54. Чем отличается абстрактный класс от интерфейса, в каких случаях что вы будете использовать?
    55. Можно ли получить доступ к private переменным класса и если да, то каким образом?
    56. Что такое volatile и transient? Для чего и в каких случаях можно было бы использовать default?
    57. Расширение модификаторов при наследовании, переопределение и сокрытие методов. Если у класса-родителя есть метод, объявленный как private, может ли наследник расширить его видимость? А если protected? А сузить видимость?
    58. Имеет ли смысл объявлять метод private final?
    59. Какие особенности инициализации final переменных?
    60. Что будет, если единственный конструктор класса объявлен как final?
    61. Что такое finalize? Зачем он нужен? Что Вы можете рассказать о сборщике мусора и алгоритмах его работы.
    62. Почему метод clone объявлен как protected? Что необходимо для реализации клонирования?

    Ответы. Часть 1

    1. Назовите принципы ООП и расскажите о каждом.

    Объе́ктно-ориенти́рованное программи́рование (ООП) — это методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.

    Основные принципы ООП: абстракция, инкапсуляция, наследование, полиморфизм.

    Абстракция — означает выделение значимой информации и исключение из рассмотрения незначимой. С точки зрения программирования это правильное разделение программы на объекты. Абстракция позволяет отобрать главные характеристики и опустить второстепенные.

    Пример: описание должностей в компании. Здесь название должности значимая информация, а описание обязанностей у каждой должности это второстепенная информация. К примеру главной характеристикой для «директор» будет то, что это должность чем-то управляет, а чем именно (директор по персоналу, финансовый директор, исполнительный директор) это уже второстепенная информация.

    Инкапсуляция — свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе. Для Java корректно будет говорить, что инкапсуляция это «сокрытие реализации». Пример из жизни — пульт от телевизора. Мы нажимаем кнопочку «увеличить громкость» и она увеличивается, но в этот момент происходят десятки процессов, которые скрыты от нас. Для Java: можно создать класс с 10 методами, например вычисляющие площадь сложной фигуры, но сделать из них 9 private. 10й метод будет называться «вычислитьПлощадь()» и объявлен public, а в нем уже будут вызываться необходимые скрытые от пользователя методы. Именно его и будет вызывать пользователь.

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

    Полиморфизм — свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта. Пример (чуть переделанный) из Thinking in Java:

    This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

    • Open with Desktop
    • View raw
    • Copy raw contents Copy raw contents

    Copy raw contents

    Copy raw contents

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

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

    В чем это проявляется в Java ? Бывают ситуации, когда необходимо запретить наследование от класса, переопределение некоторых методов в классе или изменение значения переменной. Например, объявление константы.

    Ключевое слово final означает завершенность и применимо к классам, методам и переменным.

    Применение final по отношению к классу объявляет класс завершенным, т.е запрещает дальнейшее наследование от такого класса.

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

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

    Вопрос:

    Возможно ли одновременное объявление класса как abstract и final ?

    Ответ:

    Нет, такое объявление недопустимо. Это логично, так как ключевое слово abstract говорит о том, что класс не является завершенным, в то время как final индификатор того, что класс полностью завершен.

    Применение final по отношению к методу объявляет метод завершенным, т.е запрещает дальнейшее переопределние такого метода.

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

    Переменная может быть объявлена как final , что позволяет предотвратить ее изменение. Для переменных примитивного типа это означает, что однажды присвоенное значение не может быть изменено. Для ссылочных переменных это означает, что после присвоения объекта, нельзя изменить ссылку на данный объект. Но сам объект, его состояние, изменить можно!

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

    Применение final к полям класса позволяет создавать неизменяемые(immutable) объекты. Т.е объекты, внутреннее состояние которых не изменяется. Грубо говоря, это объекты с правами только на чтение. Это очень удобно, так как позвоялет использовать объекты в разных потоках исполнения, ведь они потокобезопасны.

    Вопрос:

    Пусть есть класс, где все поля объявлены как final . Как вы напишите набор getter -ов и setter -ов дял такого класса?

    Ответ:

    Если все поля объявлены как final , то никаких setter -ов в таком классе быть не может, так как все поля будут проинициализированы один раз при объявлении или в теле конструктора, или блоке инициализации.

    Переменные, являющиеся полями класса и объявленные как static обязаны быть проинициализированы сразу или в статическом блоке инициализации:

    Обратите внимание на наименование переменной - это константа. Константами в Java принято называть public static final переменные класса.

    Про константы и их оформление можно прочесть тут.

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

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

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

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

    Модификатор final делает переменную константой в локальной области видимости объявления.

    Также, final может быть применен и к аргументам методов:

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

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

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

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

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

    В таких языках как Scala рекомендуемый способ объявления переменной выглядит как val , который как раз таки работает как объявление переменной с помощью final . Со временм я уверен подобный способ объявления будет и в Java .

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

    Если вы разберете пример выше, то увидите, что если вы объявили ссылку на изменяемый объект как final , то изменить значение ссылки нельзя - компилятор защищает эту ссылку, ведь вы объявили ее финальной. Но сам объект(если до него есть доступ) изменить можно!

    Это как если вы прикрутили намертво полку к стене. Саму полку уже не изменить и не снять, но вещи оттуда взять или положить можно. Разумеется, если прав доступа до такой полки хватит!

    Читайте также: