Pull to refresh

Comments 37

Какая-то странная статья, ваши вопросы по java скорее тянут на джуна, но никак не на мидла. От вас как мидла будут уже хотеть реальный опыт разработки приложений, понимание микросервисной архитектуры, rest, grpc очереди и тд.

В этом и нюанс: перечисленные Вами

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

никакого отношения к Java не имеют.

Уровень программиста (junior-middle-senior) ортогонален языку (и технологии в целом) на котором он пишет. Давайте еще Senior Spring Boot 2.7.1 Developer определим.

Вы перестаньте жить в вашем мире фантазий, на уровне мидл нет "Java разработчика", который знает java и больше ничего, такой разработчик ничего не стоит, у вас уже есть конкретная специальность (backend разработчик веб приложений, разработчик ui приложений, андройд девелопер и тд) вас берут для решения конкретной задачи иначе смысла от вас нет. И даже если вы решите будучи middle backend developer перейти в android developer вас никто никогда не наймет, пока вы не научитесь проходить интервью для андройд девелопера, там будут вопросы по Java но это далеко даже не 50% интервью.
И то что вы написали, спросят скорее для начала разговора и лишь частично, да и все эти знания должен иметь любой junior developer

В параграфе про SOLID, ответы для пп. 4 и 5 прямо совсем мимо.

Ага. А ещё прям бесит что из-за того что на подстановку так "затрачиваются" - забыли все остальное что аж выразили это в DRY. (Это я не буду тут ещё рассуждать почему ооп - недоказуемая концепция)

Этот ряд вопросов поможет Вам сориентироваться в теме многопоточности и поможет Вам понять что нужно "подтянуть"

Честное слово, сколько можно мурыжить эти wait-notify в 2022 году? Для меня такие вопросы на собесе просто красный флаг, что в данной команде никакой экспертизой по многопоточке даже не пахнет. Иначе бы более практические вещи обсуждали.

Что значит Liskov Substitution?

И я не понимаю, зачем продолжают придумывать эти вымученные примеры (к тому же ошибочные), если можно просто спросить кандидата примеры из JDK, где этот LSP нарушается.

S - Single Responsibility - означает что класс должен отвечать только за операции одного типа.

А потом эти люди имеют CRUD-репозиторий (CRUD это же один тип операций) на 2000 строк и святую уверенность, что написали все по солиду.

Допустим, у нас есть Берун, Кладун и Переберун. Если Переберун сделан на основе Трогуна или Щупуна, то где-то тихонечко плачет Клаус Песцов, ведь Берун сделан на основе Поднималы (см. Отрывалу), а Кладун на основе Отпускалы. Но зубрить надо обязательно эту англосаксонскую ересь, которую запомнить невозможно, а искать непереведено, и ересь эта изначально должна была отвечать только за микрокод и ни за что больше. Мы же о языке высокого уровня говорим, не так ли?

ASCIIx0E-0F

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

Спасибо за публикацию.
"Мы можем перегрузить статический метод, но мы не можем его переопределить, так как он принадлежит классу. "
Не можем переопределить, т.к. статика не принимает участие в полиморфизме, а не потому, что статический метод принадлежит классу, т.к. класс наследник - это уже фактически другой класс.

Кому из мидлов реально пригодилось знание структуры кучи?

Каждый раз когда мы создаем объект(практически всегда используя ключевое слово new) - этот объект хранится в heap

В яве нет способа разместить ссылочные типы на стеке?

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

Явно - нет. Расположение зависит от реализации JVM, оптимизации кода под конкретное железо, и много от чего еще. Знание структуры кучи может пригодиться для реализации высокопроизводительных алгоритмов, чтобы было как можно меньше поводов гонять GC, останавливая или замедляя мир.

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

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

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

А все эти наследования и полиморфизмы - это следствие того, что ООП изначальный неидеален, они никак не главные в ООП.

Смотрите: 1. Все методы static(вообще все); 2. Никаких переменных у объектов (вообще никаких); 3. Все необходимые данные каждый метод получает только из аргументов; 4. Все результаты своей работы каждый метод выдает только в виде ответа, т.е. не меняет переменные своего или других объектов (а куда ему деваться, переменных у объектов то нет); 5. Конструкторы не нужны (какое облегчение); 6. Наследование тоже не нужно (больше проблем, чем пользы); 7. Интерфейсы нужны (ибо это хорошо); 8. Все данные, которая обрабатывает программа объедены в иерархические структуры (и их немного, может быть вообще одна единая структура на всю программу).

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

Получилось вообще не ООП, но понятность и прозрачность кода только повысилась.

Интерфейсы нужны (ибо это хорошо)

Статичный метод может реализовать интерфейс?

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

Представляете сколько параметров будут принимать сервисы при таком подходе? Конструктор - как раз решение проблем, а не источник, имхо

А как это всё тестировать, кстати?

Статичный метод может реализовать интерфейс?

В java нельзя? Это печально, рука-лицо. В чем сакральный смысл такого запрета? А в скале можно, я щас проверил.

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

Один, два может быть три? Параметры ведь можно упаковать в струкруты.

А как это всё тестировать, кстати?

Так в том то и дело, что методы не зависящие от внешнего состояния, а зависящие только лишь от входных параметров тестировать гораздо проще и надежнее.

Упаковывать параметры в структуры просто, чтоб было меньше параметров? Это не решение, это костыль.

Смотрите. У меня есть метод сервиса. Он ожидает на вход некий коннектор к БД и вызывает внутри его метод. Теперь мне нужно при вызове сервиса передать туда не только коннектор, но и строку подключения, чтоб сервис мог работать с БД. Это нормально?

И в тему тестов, статичные методы можно мокать?

Да, именно так. Нормально. Гораздо лучше передавать параметры подключения каждый раз, чем хранить их внутри объекта (Ну это мое имхо, разумеется). Да, надо будет предварительно потратить усилия на то, чтобы продумать иерархическую структуру данных, ещё до того, как начать писать код. Ну а потом у вас все данные программы по сути будут объеденины в несколько крупных структур, которые будут в себе содержать всё. Стандартный подход, это 3 структуры: 1я содержит в себе только неизменяимую информацию (как параметры подключения к БД) у нее доступны только механизмы чтения; 2я обычная - содержит изменяемую информацию; 3я содержит только инфу, которую можно лишь добавлять, но не удалять и изменять (например логи и т.п.).

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

Т.е. при таком подходе все методы будут вместо сигнатуры f : X -> Y будут иметь сигнатуру f : APP<X> -> APP<Y>, где APP<X> содержит в себе Params, Logger и собственно сам X. (Почти все методы могут обойтись без изменяемой структуры, там где без нее не обойтись надо будет передавать и ее)

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

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

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

Чем лучше то?

Тем, что нарушается D из SOLID, т.к. мой условный сервис уровня приложения принимает на вход строку подключения (и ещё кучу низкоуровневых деталей)? Тем, что мне нужно для любого сервиса таскать весь конфиг всегда с собой и все необходимые сервисы (http, db, различные бизнесовые, всё что угодно)?

Ну и не забывайте, что в условных c# и java, статичные методы не могут быть реализацией интерфейса.

Покажите как это выглядит в скале, я что то бегло не нагуглил такое.

Все методы static(вообще все);

Интерфейсы нужны (ибо это хорошо)

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

Собственно, вы описали самый примитивный кейс использования Java + Spring. И все хорошо, пока вам не понадобились например паттерны "стратегия" или "pub-sub". Вот тут и будут нужны наследования и полиморфизмы в реальной жизни. А вовсе не для наследования foo от bar, как нас учат странные статейки.

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

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

Вот тут и будут нужны наследования и полиморфизмы в реальной жизни

Нужны будут наследования интерфейсов (т.е. просто расширение функционала интерфейса), а не наследование ооп-шных классов.

Никаких переменных у объектов (вообще никаких);

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

Все данные, которая обрабатывает программа объедены в иерархические структуры (и их немного, может быть вообще одна единая структура на всю программу).

Как вы поделите это на отдельные файлы, чтобы в большом проекте 10-ти разным девелоперам было удобно править 10 разных задач и не пересекаться по файлам или минимизировать это пересечение?

зависимости высшего уровня НЕ могут существовать без зависимостей низшего уровня

Где вы такое определение DI то нашли? И что оно значит в вашем мире?

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

Что это значит? Как класс может выполнять задачи, которые на него не возложены?

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

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

Какая структура у heap?

Heap имеет структуру пирамиды. Это означает что самый большой элемент всегда будет занимать самую высокую позицию.

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

К вопросу "В чем различия ArrayList и LinkedList?"

" каждый раз при вставке элемента будет создаваться новый массив размера n+1(где n размер массива до вставки)."

Что-то не верится, а там нет умножения на 1.5 (2) размерности? Вот реально каждый раз переаллокация?)

Тоже обратил внимание на это и вообще в статье куча неточностей

Например в вопросе про heap и stack, где написано что стек используется главным потоком, вообще то каждому потоку создаётся свой стек. Дальше не стал читать

Не знаком с Java, но вот этот пункт удивил:

stack "живет" короткий промежуток времени, в то время как heap "живет" весь "жизненный цикл" программы.

Это как так? Stack же хранит указатели на Heap?

Наверное, речь про frame, а не stack целиком.

Здравствуйте, Вам наверное стоит перепроверить информацию и сравнить некоторые утверждения с официальной документацией. Например:

"Так же существует четвёртый модификатор доступа - packege access level. Его необязательно объявлять в коде, данный модификатор означает что поле/метод будут доступны на уровне пакета или наследникам данного класса."

Это неверно т.к package-private доступен только внутри класса или пакета

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

Гораздо больше раздражает, что protected поля/методы видны в рамках пакета вообще всем.

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

Да, возможно, было бы интереснее отдельно задавать права для наследников, для пакета и для ещё кого-нибудь. Но если изобретать свой язык и стараться учесть все варианты этих "кого-нибудь", то уже слишком сложно всё получится. Интересно, кто-нибудь таким заморачивался?

ArrayList "под коробкой" использует массив, следовательно, каждый раз при вставке элемента будет создаваться новый массив размера n+1

Эм... А Вы точно специалист-то, про grow() не слышали?(и это только вторая минута чтения)

Секундочку! А разве Stack не создается для каждого потока? И почему в таком случае к нему есть доступ только у главного?

Про double braces спрашивают на собеседованиях? Статические анализаторы кода это помечают как баг, пишут, что это - антипаттерн и требуют исправить.

К тому же с Java 9 для создания неизменяемых Set и Map есть более удобная конструкция: Set.of(...), Map.of(...).

Sign up to leave a comment.

Articles