Модификатор open в kotlin где используется и что дает
Наследование, модификатор open, суперкласс
У нас уже был класс Cat, но теперь мы всё поменяем, чтобы показать принцип наследования.
Мы создадим суперкласс Animal, который будет содержать некоторые общие свойства и функции, которые будут наследоваться подклассами. В суперкласс добавим свойства image (имя файла с изображением животного), food (пища, которой питается животное, habitat (среда обитания), hunger (уровень голода животного), а также четыре функции: makeNoise() (животное издаёт свой характерный звук), eat() (что делает животное при обнаружении своего предпочтительного источника пищи), roam() (что делает животное, когда не ест и не спит), sleep() (животное засыпает).
Все животные выглядят по-разному, живут в разных местах и имеют разные гастрономические предпочтения. Это означает, что мы можем переопределить свойства, чтобы они по-разному инициализировались для каждого типа животного. Например, свойство habitat у класса Mouse будет инициализироваться значением «ground», а свойство food у Lion — значением «meat». Тоже самое с функциями. Каждый подкласс животного наследует функции от класса Animal. Какие же из этих функций следует переопределять? Львы рычат, волки воют, мыши пищат. Все животные издают разные звуки, это означает, что функция makeNoise() должна переопределяться в каждом подклассе животного.
Кроме того, можно сгруппировать некоторые виды классов, выстраивая иерархию. Например, волк и лисица относятся к семейству собачьих, и поэтому могут обладать общим поведением, которое можно абстрагировать в класс Canine. С другой стороны, лев, гепард и рысь относятся к семейству кошачьих, поэтому может быть полезно определить новый класс Feline.
Начнём с суперкласса Animal. Чтобы класс можно было использовать в качестве суперкласса, необходимо явно сообщить об этом компилятору. Для этого перед именем класса — и любым свойством и функцией, которые вы собираетесь переопределять, — ставится ключевое слово open. Тем самым вы сообщаете компилятору, что класс проектировался как суперкласс, и согласны с тем, что его свойства и функции, объявленные как открытые, будут переопределяться.
Мы объявили открытым сам класс, три свойства (кроме hunger) и три метода (кроме sleep).
Чтобы класс наследовал от другого класса, добавьте в заголовок класса двоеточие (:), за которым следует имя суперкласса. Класс становится подклассом и получает все свойства и функции того класса, от которого наследуется. В нашем случае класс Mouse должен наследовать от суперкласса Animal. Чтобы переопределить свойство, унаследованное от суперкласса, добавьте свойство в подкласс и поставьте перед ним ключевое слово override.
Переопределяем свойства image, food и habitat, унаследованные классом Mouse от суперкласса Animal, чтобы они инициализировались значениями, специфическими для Mouse.
Animal() после двоеточия (:) — вызов конструктора Animal. Он обеспечивает выполнение всего кода инициализации Animal — например, присваивание значений свойствам. Вызов конструктора суперкласса обязателен: если у суперкласса есть первичный конструктор, вы должны вызвать его в заголовке подкласса, иначе код не будет компилироваться. И даже если вы явно не добавили конструктор в свой суперкласс, помните, что компилятор автоматически создаёт пустой конструктор при компиляции кода.
Если конструктор суперкласса получает параметры, значения этих параметров должны передаваться при вызове конструктора.
При определении свойства в суперклассе с ключевым словом val вы обязаны переопределить его в подклассе, если хотите присвоить ему другое значение.
Если свойство суперкласса определяется с ключевым словом var, то переопределять его для присваивания нового значения не обязательно, так как переменные var могут повторно использоваться для других значений. Можно присвоить ему новое значение в блоке инициализации подкласса, как в следующем примере:
Если свойство в суперклассе было определено с ключевым словом val, в подклассе оно может быть переопределено как свойство var. Для этого просто переопределите свойство и объявите его с ключевым словом var. Учтите, что замена работает только в одном направлении: при попытке переопределить свойство var с ключевым словом val компилятор откажется компилировать ваш код.
Ранее говорилось, чтобы переопределить функцию или свойство, необходимо объявить их открытыми в суперклассе. При этом функция или свойство остаются открытыми в каждом из подклассов, даже если они были переопределены, так что вам не придётся объявлять их открытыми ниже по дереву. Если вы хотите запретить возможность переопределения функции или свойства ниже в иерархии классов, снабдите их префиксом final.
Хотя в классе Wolf мы видим только две функции, на самом деле класс содержит четыре функции. И мы можем вызвать любую из них.
Функция sleep наследуется от Animal, roam() от Canine (которая в свою очередь наследуется от Animal) и две функции переопределены в самом классе.
При вызове функции по ссылке на объект будет вызвана самая конкретная версия функции для этого типа объекта: то есть та, которая находится ниже всего в дереве наследования. Система сначала ищет функцию в классе Wolf. Если функция будет найдена в этом классе, то она выполняется. Но если функция не определена в классе Wolf, система идёт вверх по дереву наследования до класса Canine. Если функция определена в этом классе, система выполняет ее, а если нет, то поиск вверх по дереву продолжается. Система продолжает идти вверх по иерархии классов, пока не найдёт совпадение для функции.
Вот почему при вызове функции makeNoise() мы получим строку «Воет! У-у-у-у!», а не «Животное издаёт звук».
Наследование обеспечивает наличие функций и свойств во всех подклассах, определённых в суперклассе.
Когда вы определяете супертип для группы классов, вы можете использовать любой подкласс вместо суперкласса, от которого он наследуется. Можно написать следующее:
При вызове функции eat() будет вызвана версия класса Wolf, так как система знает, что по ссылке хранится объект Wolf.
Это даёт возможность создать массив из Animal на основе разных типов животных, но при этом каждый элемент массива будет выполнять свои функции.
Похожим образом поведёт себя функция, объявленная в другом классе, которая будет использовать в параметре Animal.
Айболит может сделать любому животному укол, так как волк и мышка являются разновидностями Animal.
Возможность использования объектов одного типа в месте, в котором явно обозначен другой тип, называется полиморфизмом. По сути, речь идёт о возможности предоставлять разные реализации функций, которые были унаследованы от другого класса.
Стоит заметить, что мы можем создать экземпляры класса Wolf и Mouse, но не должны иметь возможность создать экземпляр класса Animal, так такого абстрактного животного не существует. Для этой цели существуют абстрактные классы.
Часть вторая, Kotlin
Продолжение списка ответов на вопросы, собранные Веселиной. Вторая часть списка — вопросы о языке Kotlin.
16. MutableList vs List:
List представляет последовательный список элементов. List представляет неизменяемую (immutable) коллекцию, которая в основном только обеспечивает получение элементов по позиции. Изменяемые списки представлены интерфейсом MutableList. Он расширяет интерфейс List и позволяют добавлять и удалять элементы.
17. Kotlin features (что такого классного в Kotlin?):
Классы данных (Data Classes)
Умные приведения типов
В Kotlin необязательно явно указывать тип переменной
18. Data class — в чём преимущество:
Data классы с дефолтными значениями аргументов. Больше не нужны громадные классы-модели. Просто описываете конструктор и всё — toString, getter/setter, equals/hashCode будут сгенерированы автоматически и невидимо.
19. Модификатор open в Kotlin — где используется и что даёт:
По умолчанию класс всегда наследуется от Any (аналог Object в Java) и является закрытым (final) (в Java по умолчанию открыты). В этом случае нельзя наследоваться от него. Но мы можем наследоваться от другого конкретного класса, который явно объявлен как open или abstract.Также добавьте модификатор open ко всем свойствам и методам, которые можно переопределять.
20. Модификатор object в Kotlin — где используется и что даёт:
С его помощью можно реализовать шаблон “Одиночка». Ключевое слово object одновременно объявляет класс и создаёт его экземпляр. Также можно реализовать объект-компаньон, содержащий лишь фабричные методы, а также методы, связанные с классом, но не требующие обращения к его экземпляру. К членам такого объекта можно обращаться просто по имени класса. Ещё можно использовать для записи объекта-выражения в качестве замены анонимного внутреннего класса.
21. Что такое sealed class:
Изолированные классы используются для отражения ограниченных иерархий классов, когда значение может иметь тип только из ограниченного набора, и никакой другой. Они являются, по сути, расширением enum-классов: набор значений enum типа также ограничен, но каждая enum-константа существует только в единственном экземпляре, в то время как наследник изолированного класса может иметь множество экземпляров, которые могут нести в себе какое-то состояние.
Все ответы собраны из следующих источников:
Русские Блоги
Учебник Kotlin (три) классов, объектов и интерфейсов
Определить структуру наследования классов
Интерфейс в Котлине
Интерфейсы Kotlin аналогичны интерфейсам в Java 8: они могут содержать определение абстрактных методов (method = function) и реализацию неабстрактных методов (аналогично методам по умолчанию в Java 8), но они не могут содержать никакого состояния.
использовать interface Интерфейс определения ключевого слова:
Мы объявляем интерфейс с абстрактным методом с именем click. Все неабстрактные классы, реализующие этот интерфейс, должны предоставлять реализацию этого метода. Реализуем следующий интерфейс:
Kotlin использует двоеточие после имени класса вместо Java extends с участием implements Ключевые слова. Как и Java, класс может реализовывать любое количество интерфейсов, но может наследовать только один класс.
и Java @Override Аналогично аннотациям, используемым в Kotlin override Модификаторы для обозначения методов и свойств переопределенного родительского класса или интерфейса, используйте override МодификаторОбязательное, Он не будет компилироваться без аннотации, что позволит избежать случайной перезаписи, вызванной добавлением абстрактных методов после записи метода реализации.
Метод интерфейса может иметь реализацию по умолчанию. В Java 8 такую реализацию нужно отметить default Ключевые слова. Kotlin не требует специального логотипа, только тело метода:
При реализации этого интерфейса в Kotlin нет необходимости реализовывать метод с реализацией по умолчанию.
Но обратите внимание, что если вы реализуете этот интерфейс Kotlin в коде Java, все методы должны быть реализованы, а реализации по умолчанию нет.
Это как-то связано с реализацией метода Kotlin по умолчанию.Давайте сначала посмотрим на реализацию, чтобы понять, почему реализованы все методы в Java. Преобразуем указанные выше классы интерфейса и реализации в код Java:
Существует особый случай: если ваш класс реализует два интерфейса, и два интерфейса соответственно установили методы реализации по умолчанию с тем же именем, то на этот раз этот класс примет реализацию по умолчанию для какого интерфейса?
Ответ: ни один из них не будет использоваться. Вместо этого, если вы не отобразите реализацию этого интерфейса с тем же именем, вы получите ошибку компиляции.
модификаторы open, final и abstract: по умолчанию final
Классы по умолчанию в Java могут быть унаследованы и реплицированы, если явно не используются final Ключевые слова, которые обычно удобны, отдельные страницы вызывают некоторые проблемы. Модификации базового класса приводят к некорректному поведению самодовольства, которое называетсяХрупкий базовый класспроблема. «Эффективная Java» также рекомендует: либо спроектировать и наследовать документы, либо запретить это. Таким образом, Kotlin принимает эту идею, и значение по умолчанию является окончательным. Если вы хотите разрешить создание подкласса класса, вам необходимо использовать open Модификаторы для идентификации этого класса, но также добавляются к каждому свойству или методу, которые можно переопределить. open Модификатор.
Если вы переписываете член базового класса или интерфейса, перезаписанный член также открывается по умолчанию. Если вы хотите изменить это поведение и предотвратить продолжение перезаписи подкласса, вы можете явно пометить перезаписанный член как окончательный:
Также в Котлине abstract Класс в основном такой же, как Java, за исключением того, что по умолчанию он окончательный:
Я лично предполагаю, что, хотя интерфейс может быть реализован по умолчанию, мы все же используем его в соответствии с привычкой Java и не определяем реализацию по умолчанию в интерфейсе. Реализация по умолчанию определяется как abstract Класс может быть.
Значение модификатора текста модели в классе
Модификатор | Связанные члены | Комментарии |
---|---|---|
final | Не может быть переписан | Члены класса используются по умолчанию |
open | Можно переписать | Необходимо четко указать |
abstract | Должен быть тяжелым | Может использоваться только в абстрактных классах, абстрактные члены не могут быть реализованы |
override | Переопределить члены родительского класса или интерфейса | Если final не используется, перезаписанный член открыт по умолчанию. |
Модификатор видимости: по умолчанию публично
Модификатор видимости Котлина
Модификатор | Член класса | Объявление верхнего уровня |
---|---|---|
общедоступный (по умолчанию) | Виден везде | Виден везде |
internal | Видно в модуле | Видно в модуле |
protected | Видно в подкатегориях | — |
private | Видно в классе | Видно в файле |
Примечание, protected Модификаторы работают по-разному в Java и Kotlin. В Java к нему можно получить доступ из того же пакета protected Участник, но в Котлине protected Члены видны только в классе и его подклассах, то есть один и тот же пакет не виден.
Также обратите внимание, что функция расширения класса не может получить доступ к классу protected с участием protected член.
Кроме того, существует еще одно различие в правилах видимости между Kotlin и Java: внешний класс в Kotlin не может видеть закрытые члены своего внутреннего (или вложенного) класса.
Если вы не очень хорошо понимаете определение внутренних и вложенных классов Java или забыли подробности, вы можете прочитать этот блог:Глубокое понимание вложенных классов java и внутренних классов, анонимных классов
В Java внутренние классы содержат ссылки на внешние классы. Эту связь ссылок обычно легко игнорировать, поскольку она вызывает утечки памяти и неожиданные проблемы. Следовательно, по умолчанию в Kotlin используется вложенный класс. Если вы хотите объявить его внутренним классом, вам нужно использовать inner Модификатор.
Соответствие вложенных классов внутренним классам в Java и Kotlin
Объявление класса A в другом классе B | В Java | В Котлине |
---|---|---|
Вложенные классы (не хранят ссылки на внешние классы) | static class A | class A |
Внутренние классы (хранить ссылки на внешние классы) | class A | inner class A |
В Java через внутренний класс Outer.this Чтобы получить объект внешнего класса, а в Котлине через [email protected] Получите объект внешнего класса.
Запечатанные классы: определение структуры наследования ограниченного класса
Котлин предоставляет sealed Модификаторы используются для изменения класса, чтобы ограничить подклассы, которые должны быть вложены в родительский класс.
sealed Модификатор подразумевает, что этот класс является open Класс, вам больше не нужно его показывать, чтобы добавить open Модификатор тоже.
Что в этом хорошего? Когда вы when Обработка выражений все sealed При создании подкласса вам больше не нужно предоставлять ветку по умолчанию:
Заявлено sealed Класс-модификатор может вызывать только частный конструктор изнутри и не может его объявлять. sealed Интерфейс. Зачем? Помните правила видимости при преобразовании в байт-код Java? Если вы этого не сделаете, компилятор Kotlin не может гарантировать, что этот интерфейс будет реализован в коде Java.
В Kotlin 1.0 закрытая функция довольно строгая. Все подклассы должны быть вложенными, и подклассы не могут быть созданы как классы данных (упоминается позже). Kotlin 1.1 снимает эти ограничения и позволяет вам определять подклассы запечатанного класса в любом месте того же файла.
Объявить класс с нестандартными конструкторами или свойствами
В Java могут быть объявлены один или несколько методов построения. Kotlin аналогичен, но с небольшими изменениями: различать основной метод построения (обычно основной и краткий метод инициализации класса, объявленный вне тела класса) и подчиненный метод построения (Объявлено внутри тела класса). Также допускается добавление дополнительной логики инициализации в блок инициализации.
Класс инициализации: основной метод построения и блок оператора инициализации
Перед этим мы видели, как объявить простой класс:
Блок операторов в скобках (val nickName: String) Называется основным способом строительства. Есть две основные цели: указать параметры метода построения и определить свойства, инициализированные этими параметрами. Просмотрите преобразованный код Java, чтобы понять его рабочий механизм:
Мы также можем реализовать его в Kotlin в соответствии с этой логикой Java (на самом деле, это совершенно не нужно, это просто пример изучения ключевых слов, поэтому он точно такой же, как и выше):
Здесь появилось два новых ключевых слова: constructor Используется для запуска основного конструктора или объявления из конструктора (его можно опустить при определении основного конструктора вместе с именем класса); init Ключевое слово используется для введения блока оператора инициализации, который очень похож на блок кода построения в Java.
Этот метод записи такой же, как и class User (val nickName: String) Точно так же, вы заметили, что там слишком много простых слов val Ключевое слово, означающее, что соответствующие свойства будут инициализированы параметрами конструктора.
Конструктор также может устанавливать значения по умолчанию, такие как параметры функции:
Параметры по умолчанию эффективно уменьшают определение перегруженной конструкции, @JvmOverloads Вы также можете использовать параметры по умолчанию, если поддерживаете Java-код для создания экземпляра.
Если у вашего класса есть родительский класс, главный конструктор также должен инициализировать родительский класс. Это можно сделать, указав параметры конструктора родительского класса в ссылке на родительский класс списка базовых классов:
Если для класса не объявлен метод построения, будет сгенерирован метод построения по умолчанию, который ничего не делает, и класс, наследующий этот класс, также должен явно вызывать метод построения родительского класса:
Обратил внимание Button() Назад () Еще? В этом тоже отличие от интерфейса, в интерфейсе нет метода построения, поэтому нет () :
Если вы хотите убедиться, что класс не создается другим кодом, добавьте private :
В Java вы можете использовать метод частной конструкции, чтобы запретить создание экземпляра этого класса, чтобы выразить более общее значение: этот класс является контейнером или синглтоном статического служебного класса. Для этого в Kotlin есть встроенные функции на уровне языка. Вы можете использовать функции верхнего уровня как статические утилиты. Чтобы выразить синглтоны, вы можете использовать объявления объектов, которые будут рассмотрены в следующих главах.
Метод построения: используйте разные способы инициализации родительского класса
Параметры по умолчанию уже позволяют избежать перегрузки конструктора. Но если вы должны объявить несколько параметров конструкции, это тоже возможно.
Этот класс не объявляет главный конструктор, но объявляет два подчиненных конструктора, которые необходимо использовать. constructor Ключевое слово ведет.
Если вы хотите расширить этот класс, вы можете объявить тот же метод построения, используя super Ключевое слово вызывает соответствующий метод построения родительского класса:
Как и в Java, вы также можете использовать this Ключевое слово, вызовите другой конструктор в классе из одного конструктора.
Обратите внимание, что если основной конструктор определен, все подчиненные конструкторы должны прямо или косвенно вызывать основной конструктор:
Реализуйте свойства, объявленные в интерфейсе
В Kotlin интерфейсы могут содержать объявления абстрактных свойств:
По сути, атрибуты здесь не переменные (поля), а val Представляет метод получения, соответствующий код Java:
Мы реализуем этот интерфейс несколькими способами:
Класс PrivateUser использует краткий синтаксис для объявления атрибута в основном конструкторе. Этот атрибут реализует абстрактный атрибут пользователя, поэтому его необходимо пометить как переопределение.
В классе SubscribingUser свойство nickName реализуется настраиваемым получателем. Ни одно из этих свойств не поддерживает сохранение своего значения. У него есть только метод получения, чтобы каждый раз получать псевдоним из электронной почты называется.
Класс FacebookUser связывает атрибут nickName со значением во время инициализации. getFacebookName Метод получает информацию о пользователе через связь с Facebook, что дорого, поэтому он вызывается только один раз на этапе инициализации.
В дополнение к объявлениям абстрактных атрибутов интерфейсы также могут содержать атрибуты с геттерами и сеттерами, если они не ссылаются на поле поддержки (поля поддержки должны хранить состояние в интерфейсе, которое не допускается):
Доступ к полям поддержки через геттер или сеттер
name Атрибуты поддерживаются в полевых условиях, и Surname Атрибуты имеют только методы get. Эти два атрибута определены в Kotlin следующим образом:
Свойства поля, объявленные в Kotlin, будут генерировать методы получения и установки по умолчанию. Вы также можете изменить это поколение по умолчанию:
Изменить видимость аксессуаров
Видимость метода доступа такая же, как видимость атрибута. Но при необходимости вы можете изменить его, поместив модификаторы видимости перед ключевыми словами get и set:
В чем разница между помещением private непосредственно перед свойством и помещением его перед набором или аксессуаром get? Посмотрите на преобразованный Java-код:
При частном изменении свойств напрямую не создаются методы получения и установки. Модифицированный набор сгенерирует частный метод установки.
Методы, генерируемые компилятором: классы данных и делегаты классов
Общий метод объекта
Давайте посмотрим на распространенные в Java toString 、 equals и hashCode Как методы тиражируются в Котлине.
toString()
hashCode()
Метод hashCode обычно переписывается вместе с equals из-за общего контракта hashCode: если два объекта равны, они должны иметь одинаковое хеш-значение.
Эти три метода обычно переписываются в bean-компоненте контейнера данных и в основном автоматически генерируются инструментом, и теперь компилятор Kotlin может помочь нам в выполнении этих задач.
Категория данных: практика автоматического создания общих методов
Просто нужно быть class Добавить перед data Ключевые слова могут определять реализацию toString 、 equals и hashCode Класс метода-класс данных:
Делегирование класса: используйте ключевое слово «by»
Шаблон декоратора обычно используется в Java для добавления некоторого поведения другим классам. Суть этого режима состоит в том, чтобы создать новый класс, реализовать тот же интерфейс, что и исходный класс, и сохранить экземпляр исходного класса как поле.Метод, который имеет такое же поведение, как и исходный класс, не нуждается в изменении, но нужно только напрямую перенаправить на экземпляр исходного класса.
Одним из недостатков этого подхода является то, что он требует большого количества кода шаблона. Например, давайте реализуем декоратор для интерфейса Collection, даже если вам не нужно изменять какое-либо поведение:
Kotlin теперь обеспечивает первоклассную поддержку делегирования как функции языкового уровня. Всякий раз, когда вы реализуете интерфейс, вы можете использовать by Ключевое слово делегирует реализацию интерфейса другому объекту. Вот как рекомендуется переписать предыдущий пример:
Все реализации методов в классе исчезли, компилятор сгенерирует их, и реализация аналогична примеру DelegatingCollection. В этом случае нам нужно только переписать метод, который нам нужен для изменения поведения:
В этом примере выполняется подсчет путем переопределения методов add и addAll, а оставшаяся реализация интерфейса MutableCollection делегируется обернутому контейнеру.
ключевое слово объекта: объедините объявление класса с созданием экземпляра
Ключевое слово object в Kotlin встречается во многих ситуациях, но все они следуют одной и той же основной идее: это ключевое слово определяет класс и одновременно создает экземпляр (объект). Давайте посмотрим на разные сценарии его использования:
Объявление объекта: создать синглтон легко
Хотите узнать, как это работает? Также посмотрите преобразованный Java-код:
Вы можете видеть, что метод построения приватизирован, а экземпляр Payroll инициализируется посредством статического блока кода и сохраняется в поле INSTANCE. Вот почему этот метод необходим в Java:
Вы также можете использовать объявление объекта для создания синглтона в классе, и объявление объекта может получить доступ к частному атрибуту во внешнем классе:
Сопутствующий объект: сайт фабричных методов и статических членов
Классы в Kotlin не могут иметь статических членов: ключевое слово static Java не является частью языка Kotlin. Вместо этого Kotlin полагается на функции уровня пакета (в большинстве случаев он может заменить статические методы Java) и объявления объектов (в других случаях он заменяет статические методы Java, а также включает статические поля). В большинстве случаев рекомендуется использовать функции верхнего уровня, но функции верхнего уровня не могут получить доступ к закрытым членам класса.
В частности, как определить статические члены, которые необходимо использовать в общих фабричных методах и классах в Java? Именно так:
Сопутствующие объекты, используемые как обычные объекты
Сопутствующий объект по сути является обычным объектом и всеми сопутствующими объектами, которые могут выполнять обычные объекты, например, реализовывать интерфейсы.
Причина, по которой выглядит странно, заключается в том, что мы просто опускали имя его класса раньше, но мы также можем добавить к нему имя класса:
Если имя сопутствующего объекта опущено, именем по умолчанию будет Companion. Этот момент появился после преобразования кода в Java-код:
Следовательно, вы должны понимать, что вызов свойств сопутствующего объекта в Java выглядит так: A. Companion.newInstance() 。
Чтобы вызовы в Java имели единообразное взаимодействие, вы можете использовать аннотацию @JvmStatic для соответствующего члена для достижения этой цели. Если вы хотите объявить статическое поле, вы можете использовать аннотацию @JvmField для атрибута верхнего уровня или атрибута, объявленного в объекте.
Поскольку сопутствующий объект является обычным классом, конечно, можно объявить функции расширения:
Выражение объекта: анонимный внутренний класс для изменения формулировки
Ключевое слово object можно использовать не только для объявления одноэлементных объектов, но и для объявления анонимных объектов. Напишем следующий код, используя анонимные внутренние классы в Java:
Использование анонимных внутренних классов в Котлине:
За исключением удаления имени объекта, синтаксис такой же, как у объявления объекта. Выражение объекта объявляет класс и создает экземпляр класса, но не присваивает имя классу или экземпляру. Вообще говоря, им не нужно имя, поэтому вы должны использовать этот объект как параметр вызова функции. Если вам нужно присвоить объекту имя, вы можете сохранить его в переменной.
В отличие от анонимных внутренних классов Java, которые могут расширять только один класс или реализовывать один интерфейс, анонимные объекты Kotlin могут реализовывать несколько интерфейсов. И доступ к переменным в функции создания анонимных внутренних классов не ограничивается конечными переменными, и вы также можете изменить значение переменной в выражении объекта:
Точно так же мы смотрим на преобразованный код Java и изучаем, почему эти различия могут быть сделаны:
Вы можете видеть, что определенный нами clickCount заключен в оболочку IntRef, поэтому последний атрибут объявлен в классе упаковки.
Итак, как анонимные объекты Kotlin реализуют несколько интерфейсов? Я определил новый интерфейс, так что анонимный внутренний класс реализует два интерфейса одновременно:
Появилась обновка Согласно буквальному пониманию, это должен быть неопределенный тип и может быть принудительно введен в соответствующий интерфейс, это может не быть содержимым Java, неясно, какова конкретная реализация.