Вопросы и ответы для собеседования по Kotlin. Часть 1 — вы находитесь здесьВопросы и ответы для собеседования по Kotlin. Часть 2 Вопросы и ответы для собеседования по Kotlin. Часть 3 Вопросы и ответы для собеседования по Kotlin. Часть 4Вопросы и ответы для собеседования по Kotlin. Часть 5 (скоро)   Преимущества языка Kotlin перед Java Разница между Exception в Java и Kotlin Как перенести статичные методы из Java в Kotlin? В какой модификатор преобразуется internal в Java? Отличия в проверке на равенство == и equals() Кратко про анонимные классы и объекты, object и companion object Объявление объекта (object declaration), object как Singleton Сompanion object (также Singleton) Объект-выражение (анонимный объект/object expression) Разница между анонимным и декларируемым (объявляемым) объектом Аннотация @JvmStatic Что такое Null safety, nullable и non-nullable типы? Способы проверки значения на null (if-else, операторы "?.", "!!.", "?:") От какого класса унаследованы все остальные классы в Kotlin? Чем Any в Kotlin отличается от Object в Java? Какой тип находится на вершине иерархии типов в Kotlin? Кратко о Unit Сколько существует instance Unit (1)? Кратко о Nothing Назовите подтип всех типов в Kotlin Сколько существует instance Nothing (0)? Есть ли аналог Nothing в Java (нет)?       Дополнительно: Умные приведения Строковые шаблоны Делегирование на уровне языка Выведение типа для переменных и свойств Более гибкая работа с generics —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Одним из ключевых отличий между Java и Kotlin является подход к исключениям. В Java есть два типа исключений: checked и unchecked.  Checked исключения это те, которые должны быть обработаны в коде, иначе компилятор не позволит коду скомпилироваться. Unchecked исключения не требуют обработки в коде.   С точки зрения исключений компилятор Kotlin отличается тем, что не различает checked и unchecked исключения. Все исключения — только unchecked, поэтому нет необходимости отлавливать или объявлять какие-либо исключения (вы самостоятельно принимаете решение, стоит ли их отлавливать и обрабатывать). Такой подход был выбран разработчиками Kotlin, чтобы упростить и ускорить процесс разработки, сократив количество бойлерплейта и улучшив читаемость кода. Однако, это может привести к тому, что некоторые ошибки могут быть упущены при компиляции и проявиться только во время выполнения программы. Некоторые разработчики считают, что отказ от checked исключений является недостатком Kotlin, поскольку это может привести к ошибкам, которые могут быть предотвращены на этапе компиляции в Java. Однако, другие разработчики утверждают, что этот подход снижает количество шаблонного кода и упрощает написание программ. Подробнее: code.tutsplus.com, habr.com —————— ↑↑↑ к списку вопросов ↑↑↑ —————— В Kotlin нет статических методов, для этих целей обычно служит companion object.Для того чтобы метод из Java был представлен как статический используется аннотация @JvmStatic. Эта аннотация говорит компилятору Kotlin создать статический метод в  байт-коде, что позволяет использовать методы так же, как в Java.    Например, если у нас есть статический метод в Java:   Мы можем использовать этот метод в Kotlin, добавив аннотацию @JvmStatic:  Подробнее: kotlinlang.ru —————— ↑↑↑ к списку вопросов ↑↑↑ —————— В Java нет эквивалента модификатору доступа internal из Kotlin. При компиляции Kotlin-кода в Java-байткод, модификатор доступа internal преобразуется в модификатор public в Java.  Таким образом, все члены класса, отмеченные как internal, будут видны из любого места в том же пакете, а также из любого другого модуля, которому был разрешен доступ к этому модулю. Члены internal классов проходят через искажение имен, чтобы усложнить случайное использование их из Java и позволить перегрузку для членов с одинаковыми сигнатурами, которые не видят друг друга в соответствии с правилами Kotlin. Подробнее: 4comprehension.com, kotlinlang.ru  —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Структурное равенство (значение) — метод equals().Ссылочное равенство — оператор ==:— примитивные типы данных: сравнивает значения переменных— ссылочные типы данных (объекты, массивы): сравнивает ссылки Структурное равенство (значение) — оператор == (проверка через equals())Ссылочное равенство — оператор ===:— примитивные типы данных: сравнивает значения переменных— ссылочные типы данных (объекты, массивы): сравнивает ссылки Структурное равенство (значение) — оператор == в Kotlin это equals() в Java, т.е. в Kotlin строки можно всегда сравнивать через ==.Ссылочное равенство — оператор === в Kotlin это == в Java. Подробнее: kotlinlang.ru, baeldung.com, habr.com —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Анонимный класс — это класс, которые явно не объявлен с помощью class, наследуется от заданного класса или реализует заданный интерфейс.  Анонимный класс не всегда является синглтоном. Анонимный класс создается каждый раз при вызове соответствующего конструктора и используется только в контексте, где был создан. При этом каждый экземпляр анонимного класса имеет свое уникальное состояние и может отличаться от других экземпляров того же анонимного класса. В Kotlin анонимный класс создается следующим образом: Объекты анонимных классов полезны для одноразового использования. Экземпляры анонимных классов называют анонимными объектами, потому что они объявляются выражением, а не именем. Анонимный объект начинается с ключевого слова object. можно задавать свойства, функции, блоки инициализации; можно наследоваться от других классов и реализовывать интерфейсы; нельзя создавать конструкторы (как основные, так и вторичные). Ключевое слово object позволяет одновременно объявить класс и создать его экземпляр (т.е. объект). При этом применять его можно по-разному: object Name — это объявление объекта (оbject declaration), реализация паттерна Singleton; companion object — это объект-компаньон внутри класса (также Singleton); object — это объект-выражение (анонимный объект/object expression), не Singleton. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Объявляется объект при помощи ключевого слова object, после которого следует имя объекта. Файл, содержащий только object представляет из себя Singleton, т.е. будет создан только один экземпляр этого класса. Пример: Можно обращаться к методам и свойствам класса через имя объекта: Инициализация объявления объекта потокобезопасна и выполняется при первом доступе (лениво). —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Объекты можно объявлять внутри класса, при этом нет каких-либо ограничений по их количеству. Но только один объект можно пометить ключевым словом companion object в рамках одного класса. Синглтон-свойство companion object достигается за счет того, что он создается внутри класса в качестве статического поля. Он будет инициализирован при первом обращении к нему или при создании первого экземпляра класса, в котором он объявлен. Важно отметить, что companion object будет инициализирован первым, а затем уже будет создан экземпляр класса: Такому объекту можно не указывать свое имя, и обращаться к методам и свойствам объекта через имя содержащего его класса без явного указания имени объекта. Компилируется в public static final class на Java. Работает подобно ключевому слову static в Java. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Объект-выражение — это выражение, которое "на ходу" создает анонимный объект. Для объекта-выражения не указывается имя!Если же объекту всё-таки требуется имя, то его можно сохранить в переменной: Анонимные объекты не являются синглтонами!Каждый раз при выполнении объекта-выражения создаётся новый объект. Анонимный объект является заменой анонимным внутренним классам в Java. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— анонимный объект (object) инициализируется непосредственно при использовании; декларированный (объявляемый) объект (object Name) инициализируется лениво, в момент первого к нему доступа; вспомогательный объект (companion object) инициализируется в момент, когда класс, к которому он относится, загружен и семантически совпадает со статическим инициализатором Java. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— С помощью аннотации @JvmStatic есть возможность объявить методы по настоящему статическими, ее можно добавить как к методам object, так и к методам companion object. В этом случае метод staticFun будет действительно объявлен статическим: —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Null safety — это концепция безопасности, которая предотвращает некоторые из наиболее распространенных ошибок в программировании, связанных с использованием null-значений. В Kotlin эта концепция реализуется за счет строгой типизации и системы Nullable/Non-nullable типов данных. Nullable типы — это типы, которые могут содержать значение null. Non-nullable типы — это типы, которые не могут содержать значение null и всегда должны иметь некоторое значение. В Kotlin переменные по умолчанию являются non-nullable — это означает, что они не могут принимать значение null. Если переменная может принимать значение null, то ее нужно объявить с использованием знака вопроса (?). При использовании Nullable переменной в коде Kotlin не допустит обращение к ней без предварительной проверки на null-значение. Также Kotlin предоставляет множество функций для безопасной работы с nullable-значениями, таких как операторы elvis ?:, безопасный вызов ?. и другие. В целом, концепция Null safety помогает разработчикам избежать ошибок связанных с null-значениями, уменьшает количество ошибок в работе приложения и упрощает разработку и поддержку кода. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Kotlin разграничивает типы с поддержкой и без поддержки null-значений. Это означает, что при объявлении переменной, которая может хранить null, нужно явно объявить ее как nullable при помощи символа ?. Объявляя nullable переменную вы берёте на себя ответственность по проверке её значения. Иначе компилятор будет запрещать вызов функций для таких значений, ведь это может привести к NullPointerException. Рассмотрим все доступные способы проверки значения на null. Пожалуй, это самый простой способ проверки значения на null и скорее всего будет многим знаком. Использование оператора безопасного вызова будет предпочтительнее, так как он позволяет решить проблему меньшим количеством кода. Однако, если со значением переменной производятся какие-то сложные вычисления и перед началом вычислений нужно проверить равно ли оно null, то if-else вполне подойдёт. Оператор безопасного вызова позволяет сказать компилятору, что значением данной переменной может быть null и его стоит проверить перед дальнейшим использованием. То есть, если значение переменной languageName равно null, то компилятор не будет пытаться определить длину слова, а просто вернёт null. Если вы хотите вызвать функцию или каким-то другим способом обработать значение, отличное от null, то совместно с оператором безопасного вызова используйте функцию let. Всё, что будет указано в функции let выполнится только в том случае, если значение переменной отлично от null. Два восклицательных знака, стоящих после nullable-значения, преобразуют его к типу без поддержки null. При этом перед преобразованием никак не проверяется, что значение действительно не содержит null. Поэтому, если в процессе выполнения программы окажется, что значение, которое пытается преобразовать оператор !!, все-таки null, то останется только один выход — выбросить исключение NullPointerException. Если оно не обрабатывается кодом, программа аварийно завершится. Несмотря на удобство этого оператора, его следует использовать только там, где вы уверены, что null быть не может. Данный оператор понравится любителям NullPointerException. Он как бы говорит компилятору, что если значение переменной — null, то ТРЕБУЮ выбросить NullPointerException. Использование данного оператора крайне не рекомендуется, потому что (очевидно) это один из немногих способов словить NPE. При его использовании вы должны быть уверены, что значение переменной ни при каких обстоятельствах не может быть null. В противном случае лучше использовать оператор безопасного вызова. Оператор элвис подобен проверке на null в варианте if-else. Элвис используется для замены null каким-либо значением, принадлежащим обычно зауженному типу. В результате выражение с элвисом позволяет не увеличивать в программе количество nullable-переменных. Оператор указывается между двумя значениями. Если значение слева от оператора равно null, то применяется значение справа. Если значение languageName не равно null, его длина будет присвоена переменной size. Если languageName равно null, тогда будет присвоено значение 0. Но в любом случае переменной size будет присвоено значение типа Int, а не Int?, то есть non-null тип. Использование данного оператора с функцией let может полностью заменить проверку с помощью оператора if-else. Подробнее: bimlibik.github.io, kotlinlang.ru, younglinux.info —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Класс Any находится на вершине иерархии — все классы в Kotlin являются наследниками Any. Это стандартный родительский класс для всех классов, которые явно не унаследованы от другого класса. Именно в нем определены equals, hashCode и toString. Класс Any по назначению похож на Object в Java. Подробнее: gb.ru, kotlins.org —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Any не является полным аналогом java.lang.Object. В Object 11 методов в классе, в Any только 3 метода: equals(), hashCode() и toString(). При импорте типов Java в Kotlin все ссылки типа java.lang.Object преобразуются в Any. Поскольку Any не зависит от платформы, он объявляет только toString(), hashCode() и equals() в качестве своих членов, поэтому, чтобы сделать другие члены java.lang.Object доступными, Kotlin использует функции расширения. Несмотря на то, что классы Object и Any имеют сходства (корневые классы иерархии классов), они также имеют и отличия, связанные с языковыми особенностями Kotlin и Java: Класс Any в Kotlin является не только базовым классом для пользовательских классов, но также и супертипом для всех не-nullable типов данных, включая примитивные. В то время как в Java, класс Object является базовым классом только для пользовательских классов. Класс Any в Kotlin также имеет nullable версию Any?, которая является супертипом для всех nullable типов данных в Kotlin. В то время как в Java, класс Object не имеет nullable версии. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Аналогично Object в Java, к чему можно привести любой тип в Kotlin? Правильным ответом будет Any?. Сам по себе класс Any это почти аналог Object, однако, благодаря поддержке nullable и не-nullable типов в Kotlin мы получили Any?. Фактически, Any? соответствует любому типу и null, а Any только любому типу. Если по порядку: Any является корнем иерархии не-nullable типов. Any? является корнем иерархии nullable типов. Так как Any? является супертипом Any, то Any? находится в самом верху иерархии типов в Kotlin. Картинка для понимания: —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Тип Unit в Kotlin выполняет ту же функцию, что и void в Java. Возвращаемый тип можно не указывать, если функция ничего не возвращает. По умолчанию там будет Unit: Подробнее: gb.ru, kotlins.org —————— ↑↑↑ к списку вопросов ↑↑↑ —————— В стандартной библиотеке Kotlin Unit определён как объект, наследуемый от Any и содержащий единственный метод, переопределяющий toString(): Unit является синглтоном (ключевое слово object). Unit ничего не возвращает, а метод toString всегда будет возвращать “kotlin.Unit”. При компиляции в java-код Unit всегда будет превращаться в void. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Nothing является типом, который полезен при объявлении функции, которая ничего не возвращает и не завершается. Примеры: функция, которая выбрасывает exception или в которой запущен бесконечный цикл; функция TODO() — public inline fun TODO(): Nothing = throw NotImplementedError(); в тестах есть функция с именем fail, которая выдает исключение с определенным сообщением: Подробнее: gb.ru, kotlins.org —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Nothing в Kotlin — это т.н. bottom type, то есть он является подтипом любого другого типа. Наличие Nothing в системе типов позволяет типизировано выражать то, что без него принципиально невозможно. Bottom type — это тип, который не имеет значений и предназначен для обозначения невыполнимых ситуаций в программе. —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Nothing — класс, который является наследником любого класса в Kotlin, даже класса с модификатором final. При этом Nothing нельзя создать — у него приватный конструктор. В коде он объявлен так: —————— ↑↑↑ к списку вопросов ↑↑↑ —————— Тип Nothing является особенным, поскольку в Java ему нет аналогов. Действительно, каждый ссылочный тип Java, включая java.lang.Void, принимает в качестве значения null, а Nothing не принимает даже этого. Таким образом, этот тип не может быть точно представлен в мире Java. Вот почему Kotlin генерирует необработанный тип, в котором используется аргумент типа Nothing: —————— ↑↑↑ к списку вопросов ↑↑↑ —————— 1. Ключевые слова и операторы Kotlin: kotlinlang.ru2. Темы по Kotlin: hr-vector.com3. Шпаргалка по Kotlin: devhints.io Вопросы и ответы для собеседования по Kotlin. Часть 1 — вы находитесь здесьВопросы и ответы для собеседования по Kotlin. Часть 2 Вопросы и ответы для собеседования по Kotlin. Часть 3 Вопросы и ответы для собеседования по Kotlin. Часть 4 Вопросы и ответы для собеседования по Kotlin. Часть 5 (скоро)     Android Developer