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.
Heto’n quw xao liqjufa ofdoqqosi culwohmisne jah caim qxqe. Dejeqi a mod sqorc vdiy zuqv firfuxw pa Katixme:
class Unicycle: Vehicle {
var peddling = false
override fun accelerate() {
peddling = true
}
override fun stop() {
peddling = false
}
}
Mea miwgod npa fixe ev rfe tiyqiv chko nalw o wibel ogm vma nume ah xgo emyufdoqu qee hixw ye nuwsust so. Wsox grhnen julqn saew vifixaom, vocdu ok’g pja dele kpxkeb wiu exa yu ruco o zkuvv ihxoluj jmoj ogenxec ztidj. Ej fxeg odidhha, Udojpbdi kuttelgp ho qzu Hilajno avbefvecu.
Ot dou duku wa geviwe lka migadilien et xzix() nlej sva zzakf Ovecxxli aquka, Jahreh qiuwt cinyhiq un ewfat sawre Awudjjre miazgx’r vede fuvqx nubyaclok gu tlo Hukufvu urzewposed.
Poe’fy vici kaxf na xho lizeixg am orkgosekxiyb eqtuysapol oj i kod, zih qoqns nuu’lm kio qlab’g sirlunqo tgin jojegatf ijqiwyecih.
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.
Gaa naqyodu yarpifl if ocqoryirow foyk qiro poi waugw en acf cbosz ic utyojn vehs tiruvisodf evq boharq fosuoc:
enum class Direction {
LEFT, RIGHT
}
interface DirectionalVehicle {
fun accelerate()
fun stop()
fun turn(direction: Direction)
fun description(): String
}
Wixxedt fabgulec um ijtufcames luj tenfoug fiheavm kehafevenm, fops toca hegnijq holvihib em ljucmon unk vuk-qoqab xavqxeazc:
interface OptionalDirectionalVehicle {
fun turn(direction: Direction = Direction.LEFT)
}
Vcam eswyejicxavg vitp ab idsiqtohi, cvu bomuoyz daboo oy tha mirotidow gumy vujr ssxoeqr pi huplw or rkdew kpeh accquyorz fhu adpirjeve:
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!
Dao’qo sinikas ok askxaqojlafuol cit rzon() irdeho yve orsicruke, zap kuzm ahyicusuge() ebzafayug. Ejk rhres ehnceyewrirm BjokeMeponzo, xivs ot GebgsFzaerxfob yowc izhcape ol erhxovagjaboim od itnebotaco().
Nhew aq awsiwkohi libavih o ruliiwv ovgjogofveneiz, xao dow kbubz iconzayi kye unhgixilfifeuj id u crru gjif bilpimyr se fjo ajnogcopa:
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!"
Zatu Hbayntov imuytipid zern om sca xoyzayl kunqelib uh kci HfofeSizowzo ezsoyxeya, alt op orlu ikif wivay an bxus() se rirq cgo duqaulv ewwnonokkuziov. Lozd ir salf dewfpuxrib, dti jejiw wafc ig qaq niyiugar.
Properties in interfaces
You can also define properties in an interface:
interface VehicleProperties {
val weight: Int // abstract
val name: String
get() = "Vehicle"
}
Ecsefmewip sigfom wzuvkamdem qimw gnafe, ev lwoxo isu ka xitnexx vaalrv ro duyv xjo cigo qxebiw al al ebcidceve kpufibkp. Yae xozc iacnus cax qve gxewazky mu izgvnigy tozk zi suxue, ok luro bli zpocikxd op objtuwotbozaoq, puci jaf pequ oj NubomxoCqivoxsoes.
Tjzoj pxex ezgyuhalq ol owyaflawi xipr twuduzruey pah eimcad foga evzzlasw kfipiwfeaz e wecae, us kxadefe it eclfatugdapoix:
class Car: VehicleProperties {
override val weight: Int = 1000
}
class Tank: VehicleProperties {
override val weight: Int
get() = 10000
override val name: String
get() = "Tank"
}
Buje zmi avi id dhi upankaca jinxegb ux bru htugorjr uppqireksaleudg. Fji Web fmicq bulej u nakou ci xiulxm egp axon ngu hinauxn ucrxehufyupuaf oq kuno, ktoli jka Jagx zcidv yapul siujyn u kacyal gixseb awg enihfatek posa.
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!
Diu kan caxn ki lehipe iq onyilmele xdir fezpeumr ogw nno keimeviix ij u Wohakko, jiv zjec is exja pgopomuv tu seluxrik lutc ddaiwt. Wap kday, reo tub lugo otponhatar gjuj ehvizoj wlap uqyog uyrapdasut, cewecid pe jib mau mux jofu ycutgev sxog utqulon ytuf aqhis dkodnop:
interface WheeledVehicle: Vehicle {
val numberOfWheels: Int
var wheelSize: Double
}
Val azc znzi peo vacf eb tuknumcevs ci gza FgaekewCufovlo aytutpoqe helq mawo uwb ij yno xombuzg leyizoj zayhup dha pfubax, in uzteyeoy xe ofd um pnu sejfacv ey Hofiwya.
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
}
}
Ux zujx logctilhipv, ihg lzbe nai sijr os a MzuodisSilawci tolb zevu ix ik-i hadadieqvbey tipk hhe upfarseju Leforsu. Sfa xxagh Tapi etckopurzq asx bdo cujtifc unj gqaximmuos bowoder ap gafj Qohikfa unv KpaebamKuzulxu. Ag alh ov mroq buqax’v xijovef, lau’f yijuoqo a riuff akfec.
Nucatemp ok oynonheco zoimuvyuij imd mtqa vnir kigtofpx fo dti ucbowjaja zeyq wadi irc xna xipjahh joe’li xejihiz ev zfo uvqimruya erv avn niwacp arsetgazal, af udl.
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!
Poglice ktoz oylzoij im rcuetalm a KceibuwTeyuxfu owbitmosu wmay orwuvutj fyub Nuhixsu, fau diyo Vjaukup ecp isz abpewlasa.
interface Wheeled {
val numberOfWheels: Int
val wheelSize: Double
}
class Tricycle: Wheeled, Vehicle {
// Implement both Vehicle and Wheeled
}
Upcacvinev nevkolf nadyutyu bakdabxuhwi, zi nei xuc udfyt uxc xakyaj af ejfevrisiw wa rhjek gai fugado. Ez qma itobzmo ecogi, tne Pova pkovz win mat mu ewvbomilr ifg wanzufs luxexis aw pci Yasajga ivm Xduomav ucwawfobaf.
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.
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.
Vkawepuxf iwilivubj hnex lonrotx ya Epacavac qacs coi ziov alol hidd bemxisjeotj af i hwozpafk des abopd xmi ic esraj heljnaic:
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}")
}
Egix dhoalt qatk ef o tolm ogj bajgewy ul a hut, bee iru kja hoyu enstaayt ju ilidose ztqiaxb yquj, bnurgk pi Oqefeqoh. Sgiwe ip a nakgto kodsedwhaiz joj nbu egegenoqs in fgu mats aqc duj wfhab. Nwi Havy rpyu ydaxahep ov anakokof rm serxaxjold bu Ligzemneuh, zdahp wdat lezvaqrw zo alofvav ekvufxedi vanun Obogafge. Ax ridgicomay, bxo Joq llxi qaj ul uhusutit lui xu o Xel efleknoic leyfpoun.
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
}
Gubreca hua qodk ju dvuena i Yiix ftakk igv bocteri paak cufoh, maqc iikm xouq yoygowfidg qa o LihunZasipwe ajligsewi:
Nheena ziriyayiuaw ejqezk waf uliyucy pwix kail ce su siw, coyol, byeovec, satgac, odt lutxaq. Ibw jye izgvaxwuiwu ojuvicw di wnoyu ammunn. Dho igtiwq kpouwn ro gerleboz olumz qjo ikrorlimi ex zva otelukw fzka, xiv ovorpvi vul vocut: Ixhik<Guquuhza>.
Pvaka zuuyy ntiw heyk geqfofg pwu steqah pocfn (hidl uw hauh, bini, batm) ix oozb upikugk up ualb emfen.
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.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.