Extension Functions
https://kotlinlang.org/docs/extensions.html |
Extension Functions
Kotlin позволяет расширять класс или интерфейс новой функциональностью, не наследуясь от него и не используя шаблоны проектирования. Для того, чтобы объявить функцию-расширение, нужно указать в качестве префикса расширяемый тип. Расширения вычисляются статически. Расширения на самом деле не проводят никаких модификаций с классами, которые они расширяют. Объявляя расширение, вы создаёте новую функцию, а не новый член класса.
• Могут быть функциями или переменными.
• Под капотом - статическая функция Java, в качестве параметра - объект расширяемого типа.
val Int.toHexColor: String
get() = String.format("#%06X", 0xFFFFFF and this)
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
interface IAction {
fun someA(): Int
fun someB(): Int
}
fun IAction.sum(): Int {
return someA() + someB()
}
Ограничения
• Не могут изменить поведение класса
Extension-функции не могут изменять внутреннее состояние класса или его поведение, они лишь добавляют новые методы. Все изменения доступны только на уровне использования функции и не влияют на сам класс.
// Не может изменить внутреннее состояние класса
fun String.isEmpty(): Boolean {
return this.length == 0
}
• Не могут быть заменены (override
)
Extension-функции не могут переопределять методы класса. Они действуют как статические методы, которые «расширяют» класс, но не изменяют его фактическую реализацию.
open class Base {
open fun doSomething() {
println("Base")
}
}
fun Base.doSomething() {
println("Extension")
}
// Вызовет метод класса, а не extension-функцию
val base = Base()
base.doSomething() // Выведет "Base"
• Не могут изменять существующие методы
Extension-функции не могут изменять существующие методы класса или изменять их видимость. Они могут только добавить новые методы или функции, но не могут изменить поведение уже существующих.
// Можно только добавить новый метод
fun String.customMethod() {
println("Custom method")
}
// Не влияет на существующие методы String
"Hello".customMethod() // Выведет "Custom method"
• Не поддерживают полиморфизм
Extension-функции не поддерживают полиморфизм и не могут быть использованы для полиморфного вызова. Если в иерархии классов определены extension-функции, они не могут переопределяться в подклассах.
open class Animal
class Dog: Animal()
fun Animal.makeSound() {
println("Animal sound")
}
fun Dog.makeSound() {
println("Bark")
}
val animal: Animal = Dog()
animal.makeSound() // Выведет "Animal sound"
• Не могут быть вызваны через super
Extension-функции не могут быть вызваны через ключевое слово super
, так как они не являются частью класса, а представляют собой статические методы.
open class Base {
open fun print() {
println("Base")
}
}
fun Base.print() {
println("Extension")
}
class Derived: Base() {
override fun print() {
super.print() // Вызовет метод Base, а не extension-функцию
}
}
• Не поддерживают доступ к private
-методам
Extension-функции не могут обращаться к private
-свойствам класса, к которому они относятся. Они могут взаимодействовать только с public
-членами класса.
class MyClass {
private fun privateMethod() {}
}
fun MyClass.accessPrivate() {
// Не может обратиться к privateMethod()
}
Вопросы на собесе (9)
- Что такое extension-функции в Kotlin и зачем они нужны?
Позволяют добавлять новые функции к существующим классам без необходимости их наследования или изменения. Они нужны для улучшения читаемости кода и повышения его удобства, позволяя вызывать функции так, как если бы они были частью оригинального класса, что упрощает работу с API и библиотеками.
- Как extension-функции выглядят в Java? (работают под капотом)
Становится вызовом статического метода с передачей объекта в качестве первого параметра.
- Какие ограничения есть у extension-функций?
• Не могут изменить поведение класса.
• Не могут быть заменены (
override
).• Не могут изменять существующие методы.
• Не поддерживают полиморфизм.
• Не могут быть вызваны через
super
.• Не поддерживают доступ к
private
-методам.
- Что будет если сигнатура extension-функции совпадет с внутренней функцией класса?
Вызовется внутренняя функция, компилятор подсветит что имя занято.
- В каких случаях extension-функция не развернется в статическую функцию Java?
Если она объявлена внутри класса или внутри другой extension-функции.
- Можно ли обращаться к приватным полям класса из extension-функции?
Можно только если extension-функция объявлена внутри класса.
- Почему нельзя все функции класса сделать extension?
Потому что extension-функции не могут получить доступ к приватным свойствам и методам класса. Кроме того, они не могут переопределять методы и не поддерживают полиморфизм, что ограничивает их функциональность в сравнении с методами класса.
- Какой результат выведет функция main?
fun main() { val repository = UserRepository() println(repository.getName()) } class UserRepository { fun getName(id: Int = 4): String { return "Иван" } } fun UserRepository.getName(): String { return "Николай" }
Правильный ответ: Иван.
- Напиши свою extension-функцию filter?
fun <T> List<T>.myFilter(predicate: (T) -> Boolean): List<T> { val result = mutableListOf<T>() for (item in this) { if (predicate(item)) { result.add(item) } } return result }