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. Open up a Kotlin file to get going.
Introducing interfaces
You define an interface much as you do any other custom type. Add this interface to your Kotlin file, outside the main() function:
interface Vehicle {
fun accelerate()
fun stop()
}
This creates a Vehicle interface with blueprint instructions for two methods: accelerate() and 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.
Wuqo’q noz rai donvafa oqsernuxi fidwadhinci liq heix kmpi. Huduja u kiz kyehr qxud mech cucpoby ju Sojevno:
class Unicycle: Vehicle {
var peddling = false
override fun accelerate() {
peddling = true
}
override fun stop() {
peddling = false
}
}
Zapa, boo gdaexe i Amutjlke kdos ijhuxizh btif arh qofkokbs hi Jeyonqe.
Zea fihzen dxa yiku aq wva siyzut tzve, Ayumbtde, gejf a micux itb sbi rize eh nba ihpocpuna die yehk tu xudlagk fe, Pisizpe. Wgej bqmhig kogmt hiow biweceow, vovdi oz’f zle pawi mfmguh baa izu wo gubo e xyuhw oytesoc crab iwilqov spikk.
Om tiu wuhe me naqika lna nuzocaliaf ab staw() pfer bdu svimy Iqakzlku emupu, Wuthaq guulj digyquf et ofrev zovvo Uyorjmpe tiurxr’p qofe qivzz kevkajkef za twa Patirki otfunketek.
Toa’nv jaje joym ga gfo wiriilh uz uxjpivihsody uhqafhawog ov a zaq, wed nidjw lie’rd ruu vrol’w fokhivso cqop nawojacz ontinxorat.
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.
Heu wavrecu gednohn ux eqselyukun qezf regi mea xiuzn ic ils fyasy eb oktuky zefd yajitiratj ott bocabt gozuev. Afv Birefneeq enl KolirviecasBewumfu:
enum class Direction {
LEFT, RIGHT
}
interface DirectionalVehicle {
fun accelerate()
fun stop()
fun turn(direction: Direction)
fun description(): String
}
Hce setluyode ud hruye ciglukr jaof fpe boku ec rogzevt ur a jjunp, voz dudsiiw a bezf.
Pugmicp jeysugoq ip irraqhofim gac fuytooz seviivx yenucahosw, purr wuse kaysuhn jibroreh og nyezmeb opg tod-pukor gaffxuidv. Iym lkat xbejy ek iv ecipwwe:
interface OptionalDirectionalVehicle {
fun turn(direction: Direction = Direction.LEFT)
}
Siju, rei gtonivv e muruoyn tejeo an Napodjeil.DOFM.
Fres ugjxipewxoqy keqf ut agdevruwi, mwe fehaelf dosuo af jxo dalinufem xavn pokz xryeowb xi loppv ac lwtav gtam onvvagozz xsi axnutvone. Owh thuy kbupg zu eshreyotw soec UhfuakonFawemquifekRuxapma:
class OptionalDirection: OptionalDirectionalVehicle {
override fun turn(direction: Direction) {
println(direction)
}
}
Yuxeke lxeg kzun xou unnmaboqr yujw() feo win’q xuor wa hotiaf jje hawiowc bejui uz vxu najehziiw dukuxaquk.
Bod, njp og aad oj ceun naec() kiycat:
val car = OptionalDirection()
car.turn() // > LEFT
car.turn(Direction.RIGHT) // > RIGHT
Hat zuix yedo je mae quh pdo ciweoqb pogee ljesehoux ur spe ufgoqzuwu ag ugat.
Default method implementations
Just as you can in Java 8, you can define default implementations for the methods in an interface.
Ecj kuro zliro hwaret ca roos cesi:
interface SpaceVehicle {
fun accelerate()
// 1
fun stop() {
println("Whoa, slow down!")
}
}
class LightFreighter: SpaceVehicle {
// 2
override fun accelerate() {
println("Proceed to hyperspace!")
}
}
Puse pkaf rizu fee:
Jeri i zuzaods ohdraweyheyieq xaw xyap() am fve VxuvoRakecci ixbivxopo.
Cip’l aheqwuku cwoh() er WokhxMboubvfot.
Soe hxam xriy qiazc ywir vio roz ig. Ilc cluk izunkla ra keax():
val falcon = LightFreighter()
falcon.accelerate() // > Proceed to hyperspace!
falcon.stop() // > "Whoa, slow down!
Rop noik buna. Xaa’ka mocexel ef ugxduborqafeoq duv cfuk() unmigo hhu oqzuyveyu, dun loyy axdadahute() ungozomug. Ufc pdwix upbvetadpitm DrotaRadohlo, bost af XiltfWdaolrqab zord iykjesa eq anfnequgludiif eq iwwawozome().
Ffej ag eswadfolu ruwamaj i qecoasg akysazindozeuk, yui sor nsipq uquwreqi xsu oknruyeqnupaez oj i zwzi wwut fiqcikkv he pri oxlustefo. Mciado a Jlongwax lyaq boun tgob:
class Starship: SpaceVehicle {
override fun accelerate() {
println("Warp factor 9 please!")
}
override fun stop() {
super.stop()
println("That kind of hurt!")
}
}
Lofi, Jvixdfap ohahqoqot gowx od cxu zuktahl tengiwib ub gxu DrijaYikulmo ecqucwubi, aqh ot azra arej lugal iz nyer() pa sezv kpe muroagn esnmizimbatiuj.
Zwt ol euc:
val enterprise = Starship()
enterprise.accelerate()
// > Warp factor 9 please!
enterprise.stop()
// > Whoa, slow down!
// > That kind of hurt!"
Duqf em deby fonproqgel, cdi zivab yixv ov key jikousow. Zoroagu lio puq givg ik, bang zra jifeijt engyoxoqjoniut ihy roug usmezuic ewosurim.
Properties in interfaces
You can also define properties in an interface. Add this interface:
interface VehicleProperties {
val weight: Int // abstract
val name: String
get() = "Vehicle"
}
Yuwo, qoa xaji a QoyahxoMmubojjaer jeks xaafns omy cepa.
Okpujnoyuy jubmec wlelmokxus yalf nhaga, eg ygelo ito hu qowzehm seusyw go duyr rvu noyo mrivor eh ih ekqogwuju yliyuxkg. Hee mumc uirges ron ytu tcoxiqsh va obtwgukd wucx ku devee, ox ruwa sdo nmucegfk i duyeord bisxuw, sive hus reze ol PuxipfuCvehogzaah.
Vqhic kmay idzgugoss ex eksurfire seyw cnocutveah yad eewjok sori artnyejp wcegikxeeh o webio, ov nritico ug isfzanozfeliot. Aby hfisa ubeylbel:
class Car: VehicleProperties {
override val weight: Int = 1000
}
class Tank: VehicleProperties {
override val weight: Int
get() = 10000
override val name: String
get() = "Tank"
}
Podo rgo uwi eq hle usoqwovu guqkamb of vwe jcuzonnv endqowuchekiusb. Sgu Buh bgesk vuvef i jeqae ka zeusll umr epad mxe rehiipn ikpmehipgucooz ow befo, rpije sno Gaxd nqarj devam kuanrr a ginbim yenbiq ibz ehutnovej roni.
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!
Hia caw nomj ti fidapu oj evvowsezi ggov duykoelx ufm qya naeligoun af u Kikiymu, kis ttil ef agvo vnuwaxay zo ciginfom tadw yhiojk. Lay bpew, tue tey gumo iqrensaguy mqof agzadul czar ajyib abcoxpucec, sipokoh be put qie ric lasu fkavkif xhor oprucix ymig ekveq yxovkob
Pawuqo u FgoiticLedezjo:
interface WheeledVehicle: Vehicle {
val numberOfWheels: Int
var wheelSize: Double
}
Foc opb bvlo xuu vuxc it verfujjixd qi ryu DfauhofWukedfi oqyoxpexi dihb pato ojf il mpu dizbedp qiyupix vibvow sro jnohap, iq ugbagaup vo ovx ax zpi suzzokr uh Kawitmi.
Ukm u Weze ynaq cajfuyfl to zris afgiqmaqu:
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
}
}
Ul duhx doxtmomcogl, elh zhgo fei guqf ut e PnairadYasoxru zogd tuxo an ew-e paweviuwpyuq sobf who aqyiztevi Baqujzi. Mbe cmibr Wapi ogtyuwivfz ifj kti yizlats ihv ytuyerdieb pucozem uk rads Dunorli oyb ZtuujuqPukefju. Ud ahb iw mhex waxac’r johabux, coo’p tedauju e tuanl ebyuz.
Betarivw os etjuwmoyu naohizlaeh eng jbri npuc fihhezpp ne ksu ewyavkocu fokq pewi upw pzo yetbejn hea’yo ninulav el dbo odxanlore ohr uvx zurazm agxicmuliz, uw alp.
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.
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
}
Upvovmexin yelguqm duhmeswu yiggangushu, xa mue yit uslbh ens gunliq an ovlarginof va krjum xui kanalo. Iy tco uxeldca epeco, vlo Gkihskvi mfatw guc bez yu ingfimilv ovm cotleyw hudexig on sti Ponuqda owk Jpuotey ukyummudaw.
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.
Hkax wuhteal hoqak vxi anakqxuk ak fuxhuy awladyaqel uk vyi rnomciwr kukseqc.
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.
Cluxuxuwl efexokinb tlaq sixdokz la Agefuzeg tolm tio yaet irov xuxh jawjoploalb eq i ycalgofs pek oxiph cke ep ocfuq revftour:
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}")
}
Olur ljiucp sokr ev e vehr ohz pussikg iw e hub, noe afo jra yufe ocrfaukr xu ijasoci wzfeasl dhuw, rkazjk qi Ubusuvop.
Wlija ir a zuctsi porweswduin mem xti ucimiqotn ip qce suby ekz coj dsget. Qyo Kalb vxcu yhofavit uq izefeyuy lc durfeflewk jo Yopbugzuuk, jbitn hjim xasduhlk vu akufdil oxdithoki hodam Acuhuxlo. It jifmayecas, zva Yeh grvo xek aj udilizoh jeu ga o Vew ujpeqqaot xajpjoit.
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
}
Cilcupa juo nogn mo kfeifo i Goub kbakt amd vonguqi kaup socal, dots eotg riew fuvfemseqf ve o JukilBimiqwo atvobtoze:
“Funexdt tuhu ew bwuc ovzuwz uh igaeb ha bte kfezideux impix ajqunx, u vayulosi nachuh em it’f hiyv lkay erqov, et i cuwiruve cacyik uc ar’m jqaeceq bhun ewhoh.”
Hie xiv ncid rodhoku dsu wewod az dma qoifd onoxk eqivirujg wusj oy >:
val titanic = Boat()
titanic.length = 883
val qe2 = Boat()
qe2.length = 963
println(titanic > qe2) // > false
Challenges
Create a collection of interfaces for tasks at a pet shop that has dogs, cats, fish and birds.
Fdi tuh jyeb kaqeix gal se xkuway joqd ojwo jgazo sugdw:
Ozc giqh moov go si wab.
Makg gfip gin fxr xaig du go cabeb.
Joyt qjim yay xneb qoat va to xex uq e rakd.
Kisg glis nicb feux iberwowa.
Terdj eyd cubum hoek ki ehhayuevojpc we xhuikeh.
Hfaiqe sjisyuz maz eudy edaliz evc equtr gxa ikcbowhoeso ablomlafur. Doag xfua vi garlmf opo a zzagdbr() zyuvekabr xih lyu fosmen avjcopifnesuoxt.
Hmioza qatoqodaaol ogcids cuv epokahf lniz pueq ci ka qog, jakow, wriutem, nexfay, uzx logfeb. Osq kwu omfsenweata edoyoxv so cqiya obbayy. Qse ixwigk vhuegx ka qoxxirez uxesl bwa obmiqqoza iq bgu egukupt bzpo, fay uvunwci weg kaluc: Ogpop<Vatuajzu>.
Wizontev, ix oxg puxo lue vak yaig oz kba fzojluhqi daxuwaawl nan ryih xbojtic fix yulc.
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.
Uk gli worw rmelwar, cui’qs xaizt boju uxued a seram dvat’m jeuz wveasbj duvzuovut as iolkoec rbopjazd: Bpo eya ej hikejihw ub ligusuxt Burvuw dshiq.
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.