Собеседование по Java – ООП (вопросы и ответы). Часть 3

Третья часть ответов и вопросов для собеседования по ООП в Java.

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

Собеседование по Java – ООП (вопросы и ответы). Часть 1
Собеседование по Java – ООП (вопросы и ответы). Часть 2

Вопросы. Часть 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).
  • Как и у других внутренних классов, объявление переменной с именем, которое уже занято, затеняет предыдущее объявление.
  • Вы не можете определять статические члены анонимного класса.

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

44. Как связан любой пользовательский класс с классом Object?

Все классы являются наследниками суперкласса Object. Это не нужно указывать явно. В результате объект Object может ссылаться на объект любого другого класса.

45. Расскажите про каждый из методов класса Object.

  • public final native Class getClass() — возвращает в рантайме класс данного объекта.
  • public native int hashCode() — возвращает хеш-код
  • public boolean equals(Object obj) — сравнивает объекты.
  • protected native Object clone() throws CloneNotSupportedException — клонирование объекта
  • public String toString() — возвращает строковое представление объекта.
  • public final native void notify() — просыпается один поток, который ждет на “мониторе” данного объекта.
  • public final native void notifyAll() — просыпаются все потоки, которые ждут на “мониторе” данного объекта.
  • public final native void wait(long timeout) throws InterruptedException — поток переходит в режим ожидания в течение указанного времени.
  • public final void wait() throws InterruptedException — приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() методы для этого объекта.
  • public final void wait(long timeout, int nanos) throws InterruptedException — приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() для этого метода, или пока не истечет указанный промежуток времени.
  • protected void finalize() throws Throwable — вызывается сборщиком мусора, когда garbage collector определил, что ссылок на объект больше нет.

46. Что такое метод equals(). Чем он отличается от операции ==.
47. Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода?
48. Если equals() переопределен, есть ли какие-либо другие методы, которые следует переопределить?
49. В чем особенность работы методов hashCode и equals? Каким образом реализованы методы hashCode и equals в классе Object? Какие правила и соглашения существуют для реализации этих методов? Когда они применяются?

Это метод, определенный в Object, который служит для сравнения объектов. При сравнении объектов при помощи == идет сравнение по ссылкам. При сравнении по equals() идет сравнение по состояниям объектов (реализация метода equals для нового созданного класса ложится на плечи разработчиков). С точки зрения математики equals() обозначает отношение эквивалентности объектов. Эквивалентным называется отношение, которое является симметричным, транзитивным и рефлексивным.

  • Рефлексивность: для любого ненулевого x, x.equals(x) вернет true;
  • Транзитивность: для любого ненулевого x, y и z, если x.equals(y) и y.equals(z) вернет true, тогда и x.equals(z) вернет true;
  • Симметричность: для любого ненулевого x и y, x.equals(y) должно вернуть true, тогда и только тогда, когда y.equals(x) вернет true.
  • Также для любого ненулевого x, x.equals(null) должно вернуть false
При переопределении equals() обязательно нужно переопределить метод hashCode(). Равные объекты должны возвращать одинаковые хэш коды.

Хеш-код — это число. Если более точно, то это битовая строка фиксированной длины, полученная из массива произвольной длины. В терминах Java, хеш-код — это целочисленный результат работы метода, которому в качестве входного параметра передан объект.

Этот метод реализован таким образом, что для одного и того же входного объекта, хеш-код всегда будет одинаковым. Следует понимать, что множество возможных хеш-кодов ограничено примитивным типом int, а множество объектов ограничено только нашей фантазией. Отсюда следует утверждение: “Множество объектов мощнее множества хеш-кодов”. Из-за этого ограничения, вполне возможна ситуация, что хеш-коды разных объектов могут совпасть.

Здесь главное понять, что:

  • Если хеш-коды разные, то и входные объекты гарантированно разные.
  • Если хеш-коды равны, то входные объекты не всегда равны.

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

Статья с хабра по equals и hashCode: http://habrahabr.ru/post/168195/

50. Какой метод возвращает строковое представление объекта?

someObject.toString();

51. Что будет, если переопределить equals не переопределяя hashCode? Какие могут возникнуть проблемы?

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

52. Есть ли какие-либо рекомендации о том, какие поля следует использовать при подсчете hashCode?

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

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

Будут. При обращении по ключу мы можем не найти значение.

54. Чем отличается абстрактный класс от интерфейса, в каких случаях что вы будете использовать?

Абстрактные классы используются только тогда, когда есть «is a» тип отношений; интерфейсы могут быть реализованы классами которые не связаны друг с другом.

Абстрактный класс может реализовывать методы; интерфейс может реализовывать статические методы начиная с 8й версии.

Интерфейс может описывать константы и методы. Все методы интерфейса по умолчанию являются публичными (public) и абстрактными (abstract), а поля — public static final. С java 8 в интерфейсах можно реализовывать default и статические методы.

В Java класс может наследоваться (реализовывать) от многих интерфейсов, но только от одного абстрактного класса.

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

55. Можно ли получить доступ к private переменным класса и если да, то каким образом?

56. Что такое volatile и transient? Для чего и в каких случаях можно было бы использовать default?

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

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

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

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

58. Имеет ли смысл объявлять метод private final?

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

59. Какие особенности инициализации final переменных?

  • Для поля. Поле помеченное при помощи слова final не может изменить свое значение после инициализации.
    Не статическое final поле можно инициализировать: при описании, в конструкторе (во всех), в статическом блоке, в динамическом блоке.
    Статическое final поле (static final) инициализируется либо в статическом блоке, либо при описании.
  • Значение локальных переменных, а так же параметров метода помеченных при помощи слова final не могут быть изменены после присвоения.

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

К конструктору не применимо ключевое слово final.

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

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

62. Почему метод clone объявлен как protected? Что необходимо для реализации клонирования?

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

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

Собеседование по Java – ООП (вопросы и ответы). Часть 1
Собеседование по Java – ООП (вопросы и ответы). Часть 2

Часть ответов взята из http://alykoff.github.io/blog/2013/06/22/java-core-54-voprosa/
Share Button
56
68323 Total Views 5 Views Today

7 thoughts on “Собеседование по Java – ООП (вопросы и ответы). Часть 3

  1. Андрей:

    В 54 вопросе маленькое дополнение, к

    интерфейс может реализовывать статические методы и начиная с 8й версии.

    + default методы с 8 версии

  2. stepan549:

    59. Какие особенности инициализации final переменных?
    Для поля. Поле помеченное при помощи слова final не может изменить свое значение после инициализации (инициализируется либо при описании, либо в конструкторе/статическом блоке).
    — Если final без static то ИЛИ в динамическом блоке, ИЛИ во ВСЕХ конструкторах, ИЛИ при описании.
    -Если final static то то ИЛИ в статическом блоке, ИЛИ при описании, ИЛИ по умолчанию.

    1. Разделил ответ на static\ не static и дописал про все конструкторы. По умолчанию final static int a; не скомпилируется на 0.

  3. Vladimir:

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

    Для volatile переменной JVM гарантирует синхронизацию для операций чтения/записи, но не гарантирует для операций изменения значения переменной

    1. И этот ответ тоже не полный. Внутренности работы с кешем проца и java машиной явно не влезут в этот раздел. Но всё равно добавил, спасибо.

  4. chesteryo:

    Не статическое final поле можно инициализировать: при описании, в конструкторе (во всех), в статическом блоке, в динамическом блоке.

    Может я чего-то не понимаю? В статическом контексте ведь нет доступа к инстанс-переменным.

Добавить комментарий