image

Мы публикуем серию статей для подготовки к собеседованиям Java-разработчиков. Будем рассказывать о том, как разработчику успешно пройти собеседование и не поседеть во время чтения тонн мануалов. Мы не пытаемся создать энциклопедию, в которой будут отражены тысячи вопросов на интервью, но поможем понять – о чем могут спрашивать и как отвечать на сложные вопросы, чтобы избежать стресса. Итак, первый материал посвящен базовому уровню языка программирования Java Core.

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

Давным-давно,
в далекой-далекой галактике…

Юного Люка Скайуокера мучает разного рода вопросами пытливый мастер Йода. А Йода, как известно, писал код, когда мы еще с вами под стол ходили. Причем кодил он прямо в блокноте без дебаггера, intellij idea и прочей богомерзкой ерунды. Когда же он уставал от нововведений, то просто пихал в дисковод компьютера перфокарты…

Мир тебе, юный Люк. Вопрос мой первый слушай ты.

1. Какие есть пулы и представляют они из себя что? Расширять можно ли их?

Ответ:
Мастер Йода, пулы бывают целых чисел: Byte, Short, Integer, Long. Они представляют из себя массив, его размерность по умолчанию от -128 до 127. Хотя эту самую размерность можно менять с помощью ключа -XX:AutoBoxCacheMax=<размер>

Также есть пул Character. Это тоже массив значений от \u0000 и до \u07F. Символ \u07F — это DELETE.

Историю про перфокарты и символ таинственный этот тебе расскажу я:

Символ \u07F — это семь единиц в битовом представлении. Данные на перфокартах располагались обычно в 7 рядов (соответствующих семи битам байта). Единицам соответствовало пробитое отверстие, нулю, соответственно, отсутствие отверстия. Таким образом, байт со всеми единицами в разрядах можно было пробить поверх любого другого.

В случае ошибочной записи на перфокарту неправильные байты забивались этим символом. При исполнении же программы данный символ просто игнорировался.

Так \u07F стал обозначать DELETE или RUBOUT. Понятно, Люк?

Потрясающе, мастер.

2. Тут мудрость скрыта, над ней помедитируй. А сейчас продолжим. Слухи до меня дошли, что есть еще один пул. Правда ли это?

Ответ:
Есть пул String. В нем содержатся строки и на одну строку может быть несколько ссылок.

3. Ответишь без труда ты, сколько будет создано объектов после выполнения кода:

String str = new String(“Очень важная строка, вах!”)?

Ответ:
Два объекта. Тебе меня не провести. Вызов конструктора всегда приводит к помещению нового объекта в область, не являющуюся пулом. Смекаешь? А аргумент конструктора — тоже строка. Следовательно, она будет помещена в пул строк при условии, конечно, что там нет строки такого же содержания. Получается, что создается два объекта: один просто в heap, а другой — именно в сам пул строк.

4. Достойно рассказал. Есть же метод специальный, принудительно строку в пул строк помещает который. Знаешь про него?

Ответ:
Конечно. Это метод intern(). Он принудительно помещает строку в пул строк, если там ее еще нет, и возвращает ссылку на нее. Если же строка уже есть, то метод просто вернет ссылку на этот объект. Проще пареной репы.

Вот пример:
image

5. Заметил верно ты — строки неизменяемые. Но зачем это?

Причина 1. JVM хитрая, неизменяемость строк позволяет ей знатно экономить место. Вот, допустим, один объект, а ссылок на него три, иначе пришлось бы создавать на три ссылки — три объекта.

Причина 2. Безопасность. Отправили мы какие-либо параметры для авторизации и сидим себе уверенные в том, что именно то, что отправили, и придет. Строки-то не меняются!

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

Причина 4. А это уж сам Бог велел использовать их как ключи для HashMap. hashcode строки кэшируется в момент создания и нет никакой необходимости рассчитывать его снова.

Вот по этим причинам строки immutable.

6. Знатно рассказал. А вот эти пулы все — где хранятся-то они?

Ответ: Естественно, пулы хранятся в Heap, а ссылки в Stack.

7. А в чем вообще этих памяти областей отличия?

Ответ:
Вот основные отличия:
— Heap (она же куча) — используется всем приложением, Stack — одним потоком исполняемой программы;
— Новый объект создается в heap, в stack размещается ссылка на него. В стеке размещаются локальные переменные примитивных типов;
— Объекты в куче доступны из любого места программы, стековая память не доступна для других потоков;
— Если память стека закончилась JRE вызовет исключение StackOverflowError, если куча заполнена OutOfMemoryError;
— Размер памяти стека, меньше памяти кучи. Стековая память быстрее памяти кучи;
— В куче есть ссылки между объектами и их классами. На этом основана рефлексия.

8. И про память ты знаешь. А что можешь рассказать про Гарбач Коллектор?

Ответ:
Могу много рассказать, но давай поговорим об этом отдельно. Очень большая и интересная тема, обсудим ее в следующий раз.

9. А что такое сигнатура метода и контракт метода?

Сигнатура: название метода и параметры. Всё, больше там ничего нет.
Контракт: сигнатура метода плюс тип возвращаемого значения, а также бросаемые исключения

10. Давай обсудим вопрос явного приведения типов. Что будет, допустим, попробуем если Integer запихнуть в Byte мы?

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

11. Хорошо. Short занимает 2 байта, а Character также занимает 2 байта. Получается можем безопасно приводить эти типы друг другу мы?

Ответ:
С одной стороны да, а с другой — нет. В Character значения только положительные, а вот в Short у нас примерно от -32000 до 32000.
Следовательно, если значение не будет влезать, то будут просто-напросто отброшены старшие биты.

12. Ладно. А вот для того, чтобы long к float привести потребуется явное приведение типов?

Ответ:
Не-а. Не потребуется. Так велел Великий Бог Машина Омниссия создателям Java

13. Float зверь интересный вообще. Можно в конструкции switch case использовать его?

Нет, мастер. В этой конструкции можно использовать только целочисленные типы, а также с 7 версии Java можно String. Сравнение будет не как раньше по ссылке, а через equals.
При этом надо помнить, что строки чувствительны к регистру. А также, что оператор switch использует метод String.equals() для сравнения полученного значения со значениями case, поэтому обязательно нужна проверку на NULL во избежание NullPointerException.

14. Многое узнать ты можешь еще, падаван. Это только начало. Про принципы ООП поговорим. Известно ли то самое правильное определение инкапсуляции тебе?

Ответ:
Конечно, мастер Йода. Инкапсуляция — это объединение данных и методов работы с этими данными в одной упаковке.

15. Знаком ли ты с ранним и поздним связыванием вызова метода с телом его?

Ответ:
О, да.
Раннее связывание — это связывание перед запуском программы. Его еще называют статическим.
Позднее связывание или динамическое — это связывание во время выполнения программы.
Для всех методов в Java используется позднее связывание. Исключением являются final методы, а приватные методы final по умолчанию.

16. Ответ на вопрос должен дать ты: отличие композиции от агрегации и ассоциация такое что?

Ответ:
Ассоциация — это просто связь между объектами.
Агрегация — это связь по типу часть — целое.
А композиция — это связь часть — целое, при которое экземпляр части может принадлежать только одному целому.

17. Я вижу Силу в тебе. Про ClassLoader расскажешь ты мне.

Ответ:
Загрузчик классов отвечает за поиск библиотек, чтение их содержимого и загрузку классов, содержащихся в библиотеках. Эта загрузка обычно выполняется «по требованию», поскольку она не происходит до тех пор, пока программа не вызовет класс. Класс с именем может быть загружен только один раз данным загрузчиком классов.

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

Всего их три вида: загрузчик класса bootstrap, загрузчик класса расширений и системный загрузчик.

Первый загружает основные библиотеки расположенные в папке <JAVA_HOME>/jre/lib.

Второй загружает код в каталоги расширений (<JAVA_HOME>/jre/lib/ext или любой другой каталог, указанный системным свойством java.ext.dirs).
Третий загружает код, найденный в java.class.path, который сопоставляется с переменной среды CLASSPATH.

18. Про JRE упомянул ты. Что такое JRE? От JDK отличие в чем его?

Ответ:
JDK (Java Development Kit) — включает JRE и набор инструментов разработчика приложений на языке Java:
— компилятор Java (javac)
— стандартные библиотеки классов java
— документацию
— различные утилиты

JRE (java Runtime Environment) — минимально-необходимая реализация виртуальной машины для исполнения Java-приложений. Если нужно просто запустить программу, то понадобится только JRE.
В JRE входит: JVM, ClassLoader и стандартного набора библиотек и классов Java

19. Я не буду тебя спрашивать про SOLID. Лучше скажи, в нашей любимой Java нарушения этих принципов есть ли?

Ответ:
Да, допустим, нарушается принцип подстановки Барбары Лисков в коллекциях. У нас есть ArrayList параметризованный Number. И хотя Integer является наследником Number мы не сможем положить объект этого типа в коллекцию.

20. Сколько методов у функционального интерфейса может быть?

Ответ:
У функционального интерфейса может быть только один абстрактный метод. А вот дефолтных методов — сколько душе разработчика заблагорассудится.

21. Какой в них смысл? Какая суть?

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

22. Неплохо. Поговорим про исключения, а точнее про конструкцию try — catch. Скажи мне, блок finally выполняться не будет когда?

Ответ:
О, он выполняется почти всегда. Кроме как в ситуации, когда в блоке try будет бесконечный цикл, а также если кто-то надумает вызвать метод System.exit().
Если операционная система завершит работу JVM.
И ещё случай. Если блок finally будет выполняться потоком демона, а все остальные потоки не демоны завершат свое выполнение.

23. А вот такой вопрос. Если будет исключение в блоке try — catch у нас и в блоке finally. Получим в итоге что?

Ответ:
Исключение из finally. Finally затащит!

24. А если у нас конструкция try-with-resources. И произойдет исключение при ресурса закрытии, то исключение получим какое?

Ответ:
Брошенное try-блоком исключение имеет больший приоритет, чем исключения получившиеся во время закрытия.

25. Верно. А если у нас будет return и в блоке try, и в блоке finally? finally сработает ли вообще?

Ответ:
Конечно, сработает. Finally strong! Мы получим то значение, которое будет передано через return в блоке finally.

26. Вижу жажда знания твоя глубока. Поведай — что про ромбовидное наследование знаешь ты.

Ответ:
Его, можно сказать, нет в Java. Вернее, для классов множественное наследование вообще запрещено, а вот для интерфейсов есть. Можно наследовать интерфейс от двух других интерфейсов. В таком случае нужно будет просто явно вызвать через super конкретный метод родителя.

27. Про блоки инициализации и порядок их вызова знаешь ты?

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

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

28. Время обсудить equals и hashcode. Как друг с другом связаны они?

Ответ:
Между ними есть контракт.
1) Если два объекта возвращают разные значения hashcode(), то они не могут быть равны;
2) Если equals объектов true, то и хэш коды должны быть равны;
3) Переопределив equals, всегда переопределять и hashcode.

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

29. Получается, нужно переопределить equals и hashcode. hashcode. Метод equals реализовать как угодно можно?

Ответ:
Нет, конечно. Есть несколько правил:

1) Рефлексивность. Для любого заданного значения x, выражение x.equals(x) должно возвращать true;
2) Симметричность. Для двух ссылок, a и b, a.equals(b) тогда и только тогда, когда b.equals(a);
3) Транзитивность. Если a.equals(b) и b.equals©, то тогда a.equals©;
4) Консистентность. Повторный вызов метода equals() должен возвращать одно и тоже значение до тех пор, пока какое-либо значение свойств объекта не будет изменено;
5) Совместимость с hashCode(). Два тождественно равных объекта должны иметь одно и то же значение hashCode().

30. Что касается методов, то знаешь ли ты, юный Люк, как передаются параметры в метод: по ссылке или по значению? На этом вопросе сыпались даже самые продвинутые падаваны…

Ответ:
Мастер Йода, ответ на этот вопрос я знал еще в детском саду. Кто не знал ответа, тех самозабвенно пинали ногами… Параметры передаются всегда по значению. Если это примитив, то передается само значение. Следовательно, изменения никак не влияют на исходные данные. Если же это ссылка, то передается ее значение. Изменить саму исходную ссылку, понятное дело, нельзя, а вот объект по ссылке можно. Так что тут нужно быть очень осторожным в своем безудержном стремлении менять этот мир.

31. Люк, я не твой отец и даже не твой дед… Но вопрос про коллекции слушай ты.

Ответ:
О, Господи…

32. Когда нужно использовать LinkedList вместо ArrayList?

Ответ:
Представлю слово автору Framework Collection Джошуа Блоху:

image

Он-то уж точно понимает в Java. Вообще, нужно максимально избегать использования LinkedList. Единственный способ, когда есть смысл его использовать — это многократная вставка или удаление элементов в начале списка. В таком случае в ArrayList будет происходить постоянное копирование всех элементов. Хотя под капотом для этого и используется очень быстрый нативный метод System.arrayCopy(), но даже для него это слишком и он в такой ситуации категорически не вывозит.

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

33. Знаешь о нем ты?

Ответ:
Конечно, это закольцованный массив с указателями на начало и конец. Хорошая вещь.

У ArrayDeque интересный принцип увеличения размера. При первом заполнении он увеличивается в два раза, но плюс еще 2 байта. 16 + 16 + 2. Итого 34. Во второй раз также. 34 + 34 + 2. Итого 70. А потом уже увеличивается каждый раз на 50%.

34. Разработчики некоторые используют конструкцию List.of() или Map.of(). Особенность в чем?

Ответ:
List.of() как и Map.of() неизменяемы.
Map.of() под капотом представляет собой массив Object. Причем нечетные значения — это ключ, четные — значения. При коллизии происходит сдвиг вправо и так пока место не будет найдено. Этот подход называется методом открытой адресации, также известный как linear probing.

35. Через Силу увидишь вещи. Другие места. Будущее … прошлое. Старые друзья давно ушли…

*Тут Люк подумал, что маразм победил мастера Йоду окончательно, но он отогнал от себя эти мысли как наваждение Тьмы*

Мастер Йода продолжает: Расскажи про PriorityQueue мне.

Ответ:
PriorityQueue — это очередь с приоритетом. Представляет собой массив, при этом есть два условия, собственно, тот приоритет, о котором говорится в названии:
q[n] <= q[2n + 1]
q[n] <= q[2n + 2]

Это приводит к тому, что самый первый элемент будет всегда минимальным в структуре. Алгоритмическая сложность вставки/удаления элемента O(logN). По умолчанию первый раз создается массив из 11 элементов, уникальное свойство, между прочим. Так как у map по умолчанию 16 элементов, а у ArrayList — 10.

36. Ответил достойно ты. Вижу, что знаешь ты. Расскажи про разные виды итераторов.

Ответ:
Есть итератор fail-fast. С ним проблема: он генерирует исключение ConcurrentModificationException, если коллекция меняется во время итерации, но работает быстро. Пример fail-fast — Vector и Hashtable.

Допустим, вот такой код упадет с ошибкой:

image

И это печально.

А есть итератор fail-safe не вызывает исключений при изменении структуры коллекции, потому что работает с её клоном. Пример fail-safe — CopyOnWriteArrayList и итератор keySet коллекции ConcurrentHashMap. Вещь!

37. Ответ твой прекрасен. Что про красно-черные деревья скажешь вообще?

Ответ:
Красно-чёрное дерево — это бинарное дерево поиска с дополнениями. Само же бинарное дерево поиска представляет собой дерево, в котором у узла может быть ноль, один или два потомка. При этом слева значения меньше родителя, справа — больше. Вроде бы неплохо, но если мы будет добавлять отсортированные элементы, то наше дерево выродится в список и алгоритмическая сложность вместо O(logN) будет O(N).

А это плохо, поэтому и используются красно-черные деревья. У них есть дополнительные свойства, а именно появляется маркер цвета:

Корень всегда черный
У красного родителя всегда черные потомки
Листья черные и не содержат значений
Количество черных узлов в глубину одинаковое

При добавление элемента может потребоваться до двух поворотов дерева, при удалении — до трех.

38. Вот у нас есть такая коллекция TreeSet, которая под капотом как и все Set, представляет собой Map, а именно — TreeMap. Я хочу добавить туда null. Что будет?

Ответ:
Нельзя добавить null в TreeSet. Вернее добавить-то можно, но при запуске программа свалится с ошибкой. Все элементы, которые добавляем, мы должны сравнивать. Как ты сравнишь null? Никак. Это же дерево! Если только, конечно, не напишем специальный компаратор, который передадим TreeSet в конструктор.

39. А как вообще TreeSet превращается в TreeMap?

Ответ:
Очень просто, Мастер. Мы используем в качестве key добавляемое значение.

Допустим. А что же в качестве value положим мы?

Есть специальная константа, которая используется как заглушка. Она типа Object. Зовется красивым английским словом — Present.

40. Вижу на мякине не проведешь тебя. Достойно. Вопрос мой следующий ты слушай. Сколько будет занимать Node, в которой значение примитива типа byte в LinkedList и в ArrayList лежит?

Ответ:
Учитель, ты меня не уважаешь, раз спрашиваешь столь простые вопросы?

Начнем с ArrayList. Тут все предельно просто. ArrayList основан на массиве. Для примитивных типов данных осуществляется автоматическая упаковка значения, поэтому 16 байт тратится на хранение упакованного объекта и 4 байта (8 для x64) — на хранение ссылки на этот объект в самой структуре данных. Таким образом, в x32 JVM 4 байта используются на хранение одного элемента и 16 байт — на хранение упакованного объекта типа Byte. Для x64 — 8 байт и 24 байта соответственно.

С LinkedList все интереснее.

Для 32-битных систем каждая ссылка занимает 32 бита (4 байта). Сам объект (заголовок) вложенного класса Node занимает 8 байт. 4 + 4 + 4 + 8 = 20 байт. Размер каждого объекта в Java кратен 8, соответственно получаем 24 байта.

Примитив типа byte занимает 1 байт памяти, но в Java Collections Framework примитивы упаковываются: объект типа Byte занимает в памяти 16 байт (8 байт на заголовок объекта, 1 байт на поле типа byte и 7 байт для кратности 8).

Но значения от — 128 до 127 кэшируются и для них новые объекты каждый раз не создаются. Таким образом, в x32 JVM 24 байта тратятся на хранение одного элемента в списке и 16 байт — на хранение упакованного объекта типа Byte. Итого 40 байт.

Для 64-битной JVM каждая ссылка занимает 64 бита (8 байт), размер заголовка каждого объекта составляет 16 байт (два машинных слова). Вычисления аналогичны: 8 + 8 + 8 + 16 = 40 байт и 24 байта. Итого 64 байта!

Мастер Йода:
Да пребудет с нами Сила! Знаю я, что LinkedList помогал писать сам Дарт Вейдер, порождение Темной стороны он. Встретимся завтра и поговорим про память, виды ссылок, многопоточность и Гарбач Коллектор.

Люк:
До завтра, Учитель!

directed by Григорий Аверьянов, старший специалист филиала ЦК АРГО компании Neoflex.

Выражаю благодарность за советы и поддержку следующим хорошим людям: Михаилу и Алексею Деевым, Андрею Ястребову, Александру Резцову.

Комментарии (27)


  1. Cdracm
    07.07.2022 14:01
    +5

    здравствуйте, автор. я пока нашел 4 ошибки и неточности формулировок.

    1. Какие есть пулы и представляют они из себя что? Расширять можно ли их? Ответ:пулы бывают целых чисел: Byte, Short, Integer, Long

    я думаю, никакой девелопер не ответит так. вместо этого он скажет: "ну, бывает ForkJoinPool, ThreadPoolExecutor и другие. "

    3. Ответишь без труда ты, сколько будет создано объектов после выполнения кода: String str = new String(“Очень важная строка, вах!”)?Ответ: Два объекта.

    неверный ответ, я думаю. правильный ответ: не знаю, это зависит от версии, состояния класслоадеров, gc. может создаться обьект ClassLoader, может Charset, может byte[], и это все помнить не очень осмысленно.

    6. А вот эти пулы все — где хранятся-то они? Ответ: Естественно, пулы хранятся в Heap, а ссылки в Stack.

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

    11. Short занимает 2 байта, а Character также занимает 2 байта. Получается можем безопасно приводить эти типы друг другу мы?

    неверно. Short занимает от 8 до 16 байт, в зависимости много от чего.


    1. maxzh83
      07.07.2022 14:05

      я пока нашел 4 ошибки и неточности формулировок

      "Только ситхи все возводят в абсолют"


  1. p-oleg
    07.07.2022 15:01
    +4

    Гарбач Коллектор

    Сборщик мусора ужасно обозвали.


    1. neoflex Автор
      08.07.2022 15:41
      +1

      Это в формате юмора, но спасибо за комментарий, учтем в дальнейшем.


  1. upagge
    07.07.2022 16:16

    «У функционального интерфейса может быть только один абстрактный метод.»

    Дополню список ошибок. Абстрактный метод у интерфейса, это как?


    1. Nialpe
      07.07.2022 18:46

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

      Буду благодарен, если укажите мне на мои заблуждения и поясните что вас смутило.


      1. Nialpe
        07.07.2022 19:35

        Возможно, я немного коряво написал, поэтому нашел первоисточник, цитирую (docs.oracle.com):

        Note: Methods in an interface (see the Interfaces section) that are not declared as default or static are implicitly abstract, so the abstract modifier is not used with interface methods. (It can be used, but it is unnecessary.)


        1. upagge
          07.07.2022 20:18

          Да, собственно смутило, что на русском обычно так не говорят. Но видимо, вы правы.

          Даже любопытно, никогда не задумывался и не пробовал добавить к методу интерфейса abstarct :)


    1. neoflex Автор
      08.07.2022 15:42

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


  1. upagge
    07.07.2022 16:19

    Если бы на 40 вопрос от меня хотели бы такой подробный ответ, то я бы очень хотел знать к чему такие подсчеты, экстремальная экономия на серверах?))


    1. neoflex Автор
      08.07.2022 15:44

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


  1. Beholder
    07.07.2022 16:20
    +1

    Не трогайте пулы руками, ни числовые, ни строковые, не вызывайте intern(). Это путь на тёмную сторону. Скорее всего при попытке "оптимизировать" вы сделаете только хуже, потому что современные версии виртуальных машин работают уже по-другому.


    1. neoflex Автор
      08.07.2022 15:44

      Согласны с вами, но иногда спрашивают и эти моменты.


  1. ecyas
    07.07.2022 16:30
    +1

    19 вопрос. Спокойно положился Integer в ArrayList<Number>

    final List<Number> list = new ArraList<>();
    list.add(10);
    //да хоть так
    list.add(new Integer(10)); //правда с 9-ой версии такая запись deprecated, поэтому можно и так
    list.add(Integer.valueOf(10));


    1. upagge
      07.07.2022 20:24
      +1

      Речь наверное была об этом

      final List<Number> numbers = new ArrayList<>();
      final List<Integer> integers = new ArrayList<>();
      numbers = integers; // ошибка
      


      1. ecyas
        07.07.2022 22:31

        Возможно автор и имел в виду невозможность присвоения ссылки integers ссылке numbers. Но из предложения

        И хотя Integer является наследником Number мы не сможем положить объект этого типа в коллекцию

        я не вижу никакой двусмысленности. И речь идёт именно о том, чтобы положить объект Integer в коллекцию из Number.

        Возможно я слишком конкретно интерпретирую слова автора ????‍♂️


        1. upagge
          07.07.2022 22:58

          Так я не говорю, что автор прав. Предполагаю, что могло бы быть)) Скорее всего речь была бы об этом.


        1. sshikov
          07.07.2022 22:58

          Видите ли, сложно догадаться, что автор имел в виду, но: из того, что Integer наследник Number, никак не следует, что List<Integer> тоже наследник List<Number>. Или что он должен быть таким. Строго по спецификации — нет. не наследник. Именно поэтому numbers = integers; // ошибка

          И по этой же причине никакого нарушения LSP из этого факта тоже не следует. Не наследники не обязаны соблюдать LSP.

          Я уж не говорю про List<? super Integer> или List<? extends Number>, где все еще сложнее (и по-разному), один ковариантный, а другой контра.


  1. sshikov
    07.07.2022 19:30

    Данные на перфокартах располагались обычно в 7 рядов (соответствующих семи битам байта).

    Э, те перфокарты, которые я прекрасно помню, имели 12 рядов. И вы легко сможете загуглить фото такой перфокарты сами. И это как минимум две разные системы — ЕС ЭВМ и М-222 (при этом ряды в разном направлении, но короткий таки все равно 12 дырок).


  1. MichaelDeyev
    08.07.2022 09:52

    Спасибо за статью, сохранил в заметки. Перед собесами самое то:)


  1. gepron1x
    08.07.2022 11:10

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


    1. neoflex Автор
      08.07.2022 15:51

      Здравствуйте. Есть несколько разных определений понятий ООП. Это одно из них.
      Например, в статье по ссылке http://www.tonymarston.co.uk/php-mysql/abstraction.txt приведены несколько определений, причем сильно отличающихся друг от друга.


    1. neoflex Автор
      08.07.2022 15:54

      Вот еще интересная статья на эту тему www.infoworld.com/article/2075271/encapsulation-is-not-information-hiding.html


    1. kacetal
      08.07.2022 22:26

      Вы не совсем правильно понимаете, инкапсуляция это на скрытие данных, а просто объединение данных и методов. А скрытие данных это data hiding и инкапсуляция возможна без него, например в js. Или может быть наоборот, инкапсуляции нет а скрытие есть, помоему в haskell.


      1. jobber_man
        09.07.2022 00:43

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

        Поэтому в хаскеле и нет инкапсуляции, ибо изменять нечего. А в js или питоне - есть, хотя, технически, данные там спрятать довольно сложно.


  1. jobber_man
    09.07.2022 02:33

    1)Какие есть пулы и представляют они из себя что? Расширять можно ли их?

    Пулы потоков из первого, что приходит в голову. Объяснение про пул character до большинства юнглингов доходит с трудом, т.к. батя коллекцию перфокарт от деда где-то потерял. Расширять бывает можно, но от пула зависит. Пул коннектов к постргесу, например, без плясок не особо расширишь :)

    3) Ответишь без труда ты, сколько будет создано объектов после выполнения кода:

    String str = new String(“Очень важная строка, вах!”)?

    От нуля до бесконечности, в зависимости от фантазии авторов конкретной JVM.

    7) Размер памяти стека, меньше памяти кучи

    А чо, и вправду -Xmx не может быть меньше -Xss?

    Стековая память быстрее памяти кучи

    Вы меняли на вашей JVM? Разница существенна? Интуиция подсказывает, что при отсутствии gc выделение в куче должно быть за O(1). И с большой вероятностью уже в кэше процессора. Т.е. от выделения на стеке в большинстве случаев не должно сильно отличаться.

    9) А что такое сигнатура метода и контракт метода?

    Сигнатура: название метода и параметры. Всё, больше там ничего нет

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

    Про LSP и прочие контракты (например, в виде пред- и постусловий и прочего АОП на собеседовании, наверное, лучше не вспоминать).

    17) Я вижу Силу в тебе. Про ClassLoader расскажешь ты мне.

    Всего их три вида: загрузчик класса bootstrap, загрузчик класса расширений и системный загрузчик.

    Ну, это нормально, если в 2022 году юнглинг не слышал про java applets или JavaEE. Но как собеседующий мог пропустить maven и прочие штуки с кастомными класслоадерами?

    18) JRE (java Runtime Environment) — минимально-необходимая реализация виртуальной машины для исполнения Java-приложений. Если нужно просто запустить программу, то понадобится только JRE.
    В JRE входит: JVM, ClassLoader и стандартного набора библиотек и классов Java

    Ну там побольше инструментов обычно. Как минимум средства для управления сертификатами и политиками. А в старых версиях как правило и интеграция с браузерами. Ну и вендоры вольны добавить от себя все, что хотят. А стандартные класслоадеры и стандартные библиотеки от JVM вообще слабо отделимы.

    19) Я не буду тебя спрашивать про SOLID. Лучше скажи, в нашей любимой Java нарушения этих принципов есть ли?

    Да, допустим, нарушается принцип подстановки Барбары Лисков в коллекциях. У нас есть ArrayList параметризованный Number. И хотя Integer является наследником Number мы не сможем положить объект этого типа в коллекцию.

    Хотя в джаве Integer и является подтипом Number, то ArrayList<Integer>, если я правильно понимаю, подтипом ArrayList<Number> уже не является. Т.е. LSP в данном случае нарушаться не может, т.к. он тут в принципе не применим.

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

    P. S.: Я не настоящий джавист сварщик, и на "уровень юнглинг" наверняка не тяну


  1. PSA98
    10.07.2022 08:16

    Отлично, на паре вопросов даже пришлось сбегать на SO уточнить кое-что