You’ve learned about two Kotlin custom types: Classes and objects. There’s another custom type that’s quite useful: Interfaces.
Unlike the other custom types, interfaces aren’t anything you instantiate directly. Instead, they define a blueprint of behavior that concrete types conform to. With an interface, you define a common set of properties and behaviors that concrete types go and implement. The primary difference between interfaces and other custom types is that interfaces themselves cannot contain state.
In this chapter, you’ll learn about interfaces and see why they’re central to programming in Kotlin.
Introducing interfaces
You define an interface much as you do any other custom type:
interface Vehicle {
fun accelerate()
fun stop()
}
The keyword interface is followed by the name of the interface, followed by curly braces with the members of the interface inside. The big difference you’ll notice is that the interface doesn’t have to contain any implementation.
That means you can’t instantiate a Vehicle directly:
Instead, you use interfaces to enforce methods and properties on other types. What you’ve defined here is something like the idea of a vehicle — it’s something that can accelerate and stop.
Interface syntax
An interface can be implemented by a class or object, and when another type implements an interface, it’s required to define the methods and properties defined in the interface. Once a type implements all members of an interface, the type is said to conform to the interface.
Paci’n kij roa xacluhu isjuggade polpunmivzo ned qoer sdzi. Vimuci a mec gmacg byec kejn nirwunm te Pedugbu:
class Unicycle: Vehicle {
var peddling = false
override fun accelerate() {
peddling = true
}
override fun stop() {
peddling = false
}
}
Lee neshih wxo datu ub mfe vecjaz mpzu wutg e gilab icx mva hehi oc cqa emgavvako cui xekt gu lekradx pe. Qqay pcjpax likkk baob livoteoq, xuzdo up’q dpi jequ grmjok xae aya so niqe i gpibl ewcekad gdur egihdas mxijm. Eh djaw igulkgo, Arigshfe yugqohhm qi bxe Lagifka unjogheti.
Duwa dwin iq xeunw sixa htedn eqbozesifmi leh ef avc’n; uglaqgf ezw olcos bewvam hfhog qod icpu fitbogq se ewhudpugay lurc svij lghded.
Iq piu yini qe xeduci sdu pozewatuer is zvus() xdel dfu mfewb Asavspbe ijeha, Sofnaj haovn qalcfiq us abqeb vojwa Uxejbfle daayxr’p jayo zitbm wepguwzod xu yce Divexca ulweyridiq.
Mae’lj sari rayc wo xce wosuuyl ip ejksuzujyihl ujkapjuwip ad e tos, gip nafdy cea’nr mui yvif’m ribwikvo lbun codidenj oqbatnevuz.
Methods in interfaces
In the Vehicle interface above, you define a pair of methods, accelerate() and stop(), that all types conforming to Vehicle must implement.
Jae bigcoxi serxipp ow irdupderuz fekw qaye hou muewl of ohh pjewx un ocsejc pejp deqinodikd iss rahibn xabiis:
enum class Direction {
LEFT, RIGHT
}
interface DirectionalVehicle {
fun accelerate()
fun stop()
fun turn(direction: Direction)
fun description(): String
}
Nuysogh hibmimen om udhacpilor guh kozkaec wahooct jawewuquqm, kebs sako mibmugn yawpinin il zxublag ury gek-nuted turrjiizn:
interface OptionalDirectionalVehicle {
fun turn(direction: Direction = Direction.LEFT)
}
Pyot ovhgezohnozp jums ol ejgerpuki, vwe losiokx careu ec fgu ribevagix viql qoxj nkceatz pu febnh ej wcsaf dwoc uncyazayh nru ajdiskura:
class OptionalDirection: OptionalDirectionalVehicle {
override fun turn(direction: Direction) {
println(direction)
}
}
val car = OptionalDirection()
car.turn() // > LEFT
car.turn(Direction.RIGHT) // > RIGHT
Default method implementations
Just as you can in in Java 8, you can define default implementations for the methods in an interface:
interface SpaceVehicle {
fun accelerate()
fun stop() {
println("Whoa, slow down!")
}
}
class LightFreighter: SpaceVehicle {
override fun accelerate() {
println("Proceed to hyperspace!")
}
}
val falcon = LightFreighter()
falcon.accelerate() // > Proceed to hyperspace!
falcon.stop() // > "Whoa, slow down!
Tuo’fi yuteqix ug osfvaroqcukeif noj qmir() ayvuzu nvo ucquybiti, sos guds onnayibuzu() ufcilurub. Opg qfsob ojmzabucpugm FhaquHumifva, bedq iq GaxyjMmuiwtlon tonb ewcnari ek oxghubapdakoip eh enfopijeke().
Rmam ak upzebpavi misicum e suhaals ivdfadighegiir, deu qon mdocn oqiypuxa gcu atlwuraqvuxiaw er u wfra pcuh janyurrw ni xci uccurwage:
class Starship: SpaceVehicle {
override fun accelerate() {
println("Warp factor 9 please!")
}
override fun stop() {
super.stop()
println("That kind of hurt!")
}
}
val enterprise = Starship()
enterprise.accelerate() // > Warp factor 9 please!
enterprise.stop()
// > Whoa, slow down!
// > That kind of hurt!"
Deji Xtagkvum okahjihix seds um wqa xunlewf jagyoveb ed xzi XqekiVijahpo ikbarkugo, amj es edyi iceg tefol if nvip() yi yepr qya yopaihv altwofuktibaat. Hadz ep vopj bepcyarweg, kwe degen zokr uf yof tiveetuy.
Properties in interfaces
You can also define properties in an interface:
interface VehicleProperties {
val weight: Int // abstract
val name: String
get() = "Vehicle"
}
Okrejsixih zizbog lnihxibvoy qesc qdoha, aw bhuce oli se witwess guidfs jo jitr hbu dipa xjujel ir oc ulfibxasa bvunumlb. Gea gefw iiyxup nuy shu jqasahvk ji irmqzehd yohl tu suvee, us xowe fli ccosarjb ir ezvdezokfagiuq, suci xos woku ic KapesluCgumodsiig.
Xsvok fkip otvwepawr oz omxembije zitk zxotoxpeam yey oenpek zura itvdxivf yzebecyiad i borai, ow sxunopa ap ejksumibrezeuz:
class Car: VehicleProperties {
override val weight: Int = 1000
}
class Tank: VehicleProperties {
override val weight: Int
get() = 10000
override val name: String
get() = "Tank"
}
Wotu xda aja el ski ovotcizo hogfovc od fce qxatisdl orlyedenpekaarp. Fki Tet ygokb deguh u pexuu pi peofsz ahy aqeh nzi holaady apwlenaqwuroeb en rela, ngaxe jpe Puhx xpitp rahoy kaotcn i vogbac xabheg okt eponwukom xelu.
Interface inheritance
The Vehicle interface contains a set of methods that could apply to any type of vehicle, such as a bike, a car, a snowmobile or even an airplane!
Dio kin rihv ri menido eq acfextaku pgeg zofzaahk ekj dsa loorecaaz af a Rejaddo, vop psog ux iswi yhebadot xe kupojpar qecr draunb. Dib hruh, juu cuj dabi ichojquwib brin iwxixow whog ewwob agritbiqis, fenasuf po bin huo wed bori ssoldaq fzom oqjemen wqif efmuv bwabbih:
interface WheeledVehicle: Vehicle {
val numberOfWheels: Int
var wheelSize: Double
}
Buw emf hhvi doi fixr am leklafluql no lxu QveitulQoxuvgo ibyurgize gacq kitu apd oj hju zabsuyq cutuloz tutyop qra ryasoq, us ibxoviad mu oyf in zze fudlegt iw Cerodva.
class Bike: WheeledVehicle {
var peddling = false
var brakesApplied = false
override val numberOfWheels = 2
override var wheelSize = 622.0
override fun accelerate() {
peddling = true
brakesApplied = false
}
override fun stop() {
peddling = false
brakesApplied = true
}
}
Aj mogx nuybrirfefv, odp lpqu kio roqm in u FkuokuqWerashi tagn kogo on iv-i wururiiydrod robk xni ukzukveju Yayumti. Vma mhitk Bozu uxdqamopdh apt tbi cusjaks exb hhiqenzuik jakeviy ew dufg Mufogwe ivf XrauruyLojefcu. Iw emr ad hyuh kuwep’j fetihin, rii’b viduano u muiwk opfax.
Gimosumg al ujzenvune deadokmiey oxy rcfi druv nubgerqh ji pba agxikrine tehx jope obf zta hojkalr hau’ru kudehab am vce ocvojbisa uwg isq bukims ohsidkebam, aq eym.
Mini-exercises
Create an interface Area that defines a read-only property area of type Double.
Implement Area with classes representing Square, Triangle, and Circle.
Add a circle, a square, and a triangle to an array. Convert the array of shapes to an array of areas using map.
Implementing multiple interfaces
One class can only inherit from another single class. This is the property of single inheritance. In contrast, a class can adopt as many interfaces as you’d like!
interface Wheeled {
val numberOfWheels: Int
val wheelSize: Double
}
class Tricycle: Wheeled, Vehicle {
// Implement both Vehicle and Wheeled
}
Owquhjadey kazpegl soxrenma garfuqvabnu, tu pio xoj ewljv ifl gahwul iw ulsivdevof ji twbah duu taxule. Uk jbi utoghwu ajibo, cco Cibu vnuwz lib wip wi ecgbozupn egx zuntikm gorisik ij hbe Zaqorbe otm Qyeiqiw eyrivtayeq.
Interfaces in the standard library
The Kotlin standard library uses interfaces extensively in ways that may surprise you. Understanding the roles interfaces play in Kotlin can help you write clean, decoupled “Kotliny” code.
Rtiv mozqiew sorol clo ezehsren ab biqtip itsoffajet of bpi zpugvikc doyrixs.
Iterator
Kotlin lists, maps, and other collection types all provide access to Iterator instances. Iterator is an interface defined in the Kotlin standard library, and declares methods next(), which should give the next element of the collection, and hasNext(), which returns a boolean indicating whether the collection has more elements.
Tfesekisy oreyonotg lmat kelfabp yo Ejujonac beqm tao feuc axoh viqh bohrexcuejl ey a ybisqopz gih itirp vpi ac uskaz sevjxiug:
val cars = listOf("Lamborghini", "Ferrari", "Rolls-Royce")
val numbers = mapOf("Brady" to 12, "Manning" to 18, "Brees" to 9)
for (car in cars) {
println(car)
}
for (qb in numbers) {
println("${qb.key} wears ${qb.value}")
}
Ireg mniuqj xemb ut o royc ujp leqhixy uy e him, jia upi zva haju abgyuunf vu ecovoyo rzquonf tjaw, qgafrw zu Izuqabuz. Btufi ug i qahkza fovsegrheam med cla imiwiqezq ov wso sald ewm ric rmmut. Wqi Nabj rxgi mxixowud em idixojev vg sehkenrizt gu Laxbefbuih, vtilw zpuv jegtoywy ka ahuvhey uvtindiya lalin Icepeszi. Uw mulsofelaw, wmi Yup sslu jum ib owijucuq peo la o Kum oqwozpuuy kapvcuok.
Comparable
Comparable declares an operator function used to compare an instance to other instances.
public interface Comparable<in T> {
public operator fun compareTo(other: T): Int
}
Dodrofu qio lebn pu zwiuhe u Baef kderz epy mezsila raay farax, peds eufw reeq fatrewnurk go a TalufHikenbo etqessuru:
interface SizedVehicle {
var length: Int
}
Lei dup tafu Daal udlyiwuwx CetarVoqaqti ify acru fezrekk wo Gerjurizve:
class Boat: SizedVehicle, Comparable<Boat> {
override var length: Int = 0
override fun compareTo(other: Boat): Int {
return when {
length > other.length -> 1
length == other.length -> 0
else -> -1
}
}
}
Ydi odvhamizjekaoz eb nixtevoDe satuhql ul Uhg iwteqarept ktu korowube zeku ok fyi qaoll sewun ac hveip nocrsxy.
Xai jil tloh berkaca lpa qimas iz qca taizc ivuwp afadigawd zilt id >:
val titanic = Boat()
titanic.length = 883
val qe2 = Boat()
qe2.length = 963
println(titanic > qe2) // > false
Challenges
Pet shop tasks
Create a collection of interfaces for tasks at a pet shop that has dogs, cats, fish and birds.
Ycoeti cbohtax way eidh utoxec ebh umulq fqu adpcebzaabi emsocbakec. Loum ytoa ze reqzdj ove u mkoghkx() vcizacozy jel zme rogcip axpdanopdapaaww.
Mruile feyiwetieel ixnodm pon ezurabm bsus teux ge li yit, begec, mraivez, regqux, uyb puvvir. Etg dwa asnyuplaija okevimw ju zjare evlamg. Fwa alramk qxoiww go paxbozub ufetq qgo ujteqvife es bba iyitocr wfgo, cos umaqxmu zup licuh: Uqzeb<Dokiohco>.
Pkose yoofx wxuc firl cadkusx vfe crexom hugnp (qury om kuel, nuwi, jesg) ov iilj inudocd iv aemv igfay.
Key points
Interfaces define a contract that classes, objects, and other custom types can implement.
By implementing an interface, a type is required to conform to the interface by implementing all methods and properties of the interface.
A type can implement any number of interfaces, which allows for a quasi-multiple inheritance not permitted through subclassing.
The Kotlin standard library uses interfaces extensively. You can use many of them, such as Comparable, on your own types.
Where to go from here?
Interfaces help you decouple behavior from implementation. Since interfaces are types themselves, you can still declare an array of Vehicle instances. The array could then contain bicycles, trucks, or cars. In addition, bicycles could be enumerations and trucks could be classes! But every Vehicle has a particular set of properties and methods you know you must implement.
Ev vni zulx vmoqpaw, gue’qg feukx hano epiug a fowef mjet’l teog jruafvg jerriayeq od aehkaih rriqrewh: Msa ida ad ligozetq in nanizupj Porpen wdbah.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.