#java #kotlin
#java #kotlin
Вопрос:
Рассмотрим следующие классы:
open class Parent(foo: Map<a, b>)
class Child(foo: Map<a, b>): Parent(foo)
Похоже, здесь это работает, потому что определения foo
идентичны в обоих классах. Однако, когда я пытаюсь сделать
class Child(foo: Map<a, b>? = mapOf()): Parent(foo)
Это больше не работает, потому что foo
определено как необязательное в Child
классе.
Это вызывает у меня проблемы, потому что я пытаюсь инициализировать Child
класс в Java, и, очевидно, это не позволило бы мне выборочно передавать аргументы, такие как Kotlin, поэтому мне было интересно, что я мог бы сделать здесь, чтобы позволить вызывающему Java передавать null
в foo
поле, чтобы поле автоматически инициализировалось на пустой карте.
Спасибо
РЕДАКТИРОВАТЬ: Также был бы признателен, если бы кто-нибудь мог объяснить, почему Kotlin не пытался передать foo
значение по умолчанию в Child
в Parent
? Мы все знаем, что foo
in Child
в любом случае определенно не будет полным.
Комментарии:
1. Мы этого не знаем! С помощью этой подписи я могу легко создать
Child(foo = null)
, и значение по умолчанию не будет применяться!
Ответ №1:
Лучшим вариантом для клиента дочернего класса было бы не передавать какой-либо параметр вместо null, поэтому вы можете просто указать значение по умолчанию для foo map в дочернем конструкторе
class Child(foo: Map<String, String> = emptyMap()): Parent(foo)
затем компилятор kotlin сгенерирует два конструктора дочернего класса, чтобы вы могли использовать его по своему усмотрению в Java
Child child = new Child();
Child secondChild = new Child(new HashMap<>());
Комментарии:
1. Похоже, это работает хорошо, если речь идет только об одном необязательном параметре. Однако кажется, что количество вторичных конструкторов увеличится, когда мы добавим больше опций?
2. да, но если у вас есть больше параметров, то, возможно, вам вообще не нужен этот null, вы можете указать только значение параметра foo по умолчанию в дочернем классе, и компилятор kotlin сгенерирует для вас два конструктора для использования, я обновлю свой ответ
3. Мне любопытно, что произойдет, если кто-то передаст
HashMap
значение которого равно null? СкажитеHashMap<> myMap = null
.4. вы получите исключение IllegalArgumentException во время выполнения вашей Java-программы, компилятор kotlin создаст конструктор, который выглядит следующим образом (это декомпилированная версия из байт-кода)
public Child(@NotNull Map foo) { Intrinsics.checkParameterIsNotNull(foo, "foo"); super(foo); }
Ответ №2:
чтобы позволить вызывающей стороне Java передавать значение null в поле foo, чтобы поле автоматически инициализировалось для пустой карты
Если вы передадите null
(в Java или Kotlin, не имеет значения), он будет инициализирован null
. Вы можете сделать что-то вроде
class Child(foo: Map<a, b>? = null): Parent(foo ?: mapOf())
вместо этого. Или используйте @JvmOverloads
:
class Child @JvmOverloads constructor(foo: Map<a, b> = mapOf()): Parent(foo)
для создания перегрузки без параметров. На самом деле, это особый случай, когда в этом нет необходимости:
Обратите внимание, что, как описано во вторичных конструкторах, если класс имеет значения по умолчанию для всех параметров конструктора, для него будет сгенерирован общедоступный конструктор без аргументов. Это работает, даже если
@JvmOverloads
аннотация не указана.