OOP in Kotlin

Classes, objects, constructors, properties, methods, inheritance, polymorphism, and encapsulation

class object Inheritance Encapsulation

Table of Contents

1Classes

A class is a blueprint for creating objects. It defines properties (data) and methods (behavior). In Kotlin, classes are declared with the class keyword. Unlike Java, you don't need new — just call the constructor like a function.

Basic classclass Person { var name: String = "" var age: Int = 0 fun introduce() { println("Hi, I'm $name and I'm $age years old.") } } fun main() { val person = Person() // no 'new' keyword person.name = "Nikhil" person.age = 25 person.introduce() }

Class with primary constructor parameters

Concise class declarationclass Car(val brand: String, var model: String, val year: Int) { fun displayInfo() { println("$year $brand $model") } } fun main() { val car = Car("Toyota", "Camry", 2024) car.displayInfo() car.model = "Corolla" }
ConceptKotlinJava equivalent
Declare classclass Name { }class Name { }
Create instanceval obj = Name()Name obj = new Name();
Default visibilitypublic (implicit)public (implicit)
Inheritance defaultClasses are final by defaultClasses extendable unless final
data class shortcut

For model/entity classes, use data class — auto-generates equals, hashCode, toString, and copy. Covered in Data, Enum & Sealed Classes.

2Objects

Kotlin uses the object keyword for singletons, companion objects, and anonymous object expressions — reducing boilerplate compared to Java.

Object declaration (singleton)

Singleton objectobject DatabaseManager { fun connect() { println("Database connected") } val version = "1.0" } fun main() { DatabaseManager.connect() println(DatabaseManager.version) }

Companion object

A companion object belongs to the class (like Java's static members) but is a real object instance:

Companion objectclass User(val name: String) { companion object { const val MAX_NAME_LENGTH = 50 fun createGuest(): User { return User("Guest") } } } fun main() { println(User.MAX_NAME_LENGTH) val guest = User.createGuest() println(guest.name) }

Object expression (anonymous object)

Anonymous objectfun main() { val clickHandler = object { val id = 1 fun onClick() = println("Clicked! id=$id") } clickHandler.onClick() }
KeywordPurposeInstances
object Name { }SingletonExactly one
companion objectFactory methods, constantsOne per class
object : Type { }Anonymous implementationCreated inline
Android: Companion objects often hold newInstance() factory methods for Fragments and static-like constants.

3Constructors

Kotlin has a primary constructor (in the class header) and optional secondary constructors. Initialization logic goes in init blocks.

Primary constructor

Primary constructor with initclass Student(val id: Int, var name: String) { init { require(name.isNotBlank()) { "Name cannot be blank" } println("Student created: $name") } } fun main() { val s = Student(1, "Alex") }

Secondary constructor

Secondary constructorclass Rectangle(val width: Double, val height: Double) { constructor(side: Double) : this(side, side) // square fun area() = width * height } fun main() { val square = Rectangle(5.0) val rect = Rectangle(4.0, 6.0) println(square.area()) // 25.0 println(rect.area()) // 24.0 }

Constructor visibility

Private constructor — factory patternclass Logger private constructor(val tag: String) { companion object { fun create(tag: String): Logger { return Logger(tag) } } fun log(msg: String) = println("[$tag] $msg") } fun main() { val logger = Logger.create("App") logger.log("Started") }
ConstructorSyntaxNotes
Primaryclass X(val a: Int)One per class; can have default values
Secondaryconstructor(...) : this(...)Must delegate to primary with this
init blockinit { }Runs when instance is created; can have multiple
Default parameter values

Often you can replace multiple secondary constructors with one primary constructor using default arguments — see Functions.

4Properties

In Kotlin, fields are accessed through properties — pairs of getters and setters generated automatically. Declare with val (read-only) or var (read-write) in the class body or constructor.

Property basicsclass Account(val id: Int, var balance: Double) { val isEmpty: Boolean get() = balance == 0.0 var holderName: String = "Unknown" set(value) { field = value.trim() } } fun main() { val acc = Account(1, 500.0) acc.holderName = " Nikhil " println("${acc.holderName}: ${acc.balance}, empty=${acc.isEmpty}") }

Custom getter and setter

Computed propertyclass Temperature(celsius: Double) { var celsius: Double = celsius set(value) { field = value.coerceIn(-273.15, 1000.0) } val fahrenheit: Double get() = celsius * 9 / 5 + 32 } fun main() { val temp = Temperature(25.0) println("${temp.celsius}°C = ${temp.fahrenheit}°F") }

lateinit and lazy

lateinit and lazy propertiesclass ViewModel { lateinit var repository: UserRepository // initialized later val config by lazy { println("Loading config...") loadConfig() } } fun loadConfig() = mapOf("timeout" to 30)
KeywordUse case
valRead-only property (getter only)
varMutable property (getter + setter)
fieldReference backing field in custom getter/setter
lateinit varNon-null var initialized after construction
by lazyComputed once on first access
No Java-style fields: Kotlin discourages public fields — use properties. Java getters/setters map to Kotlin properties automatically in interop.

5Methods

Methods (member functions) define behavior inside a class. They can access properties and other methods of the same instance using this (optional in most cases).

Member functionsclass Calculator { fun add(a: Int, b: Int): Int = a + b fun subtract(a: Int, b: Int) = a - b fun printResult(label: String, value: Int) { println("$label: $value") } } fun main() { val calc = Calculator() calc.printResult("Sum", calc.add(10, 5)) calc.printResult("Diff", calc.subtract(10, 5)) }

Overriding methods

overrideopen class Animal(val name: String) { open fun speak() { println("$name makes a sound") } } class Dog(name: String) : Animal(name) { override fun speak() { println("$name says Woof!") } } fun main() { Dog("Buddy").speak() }

Visibility modifiers on methods

ModifierVisible from
publicEverywhere (default)
privateSame class only
protectedClass and subclasses
internalSame module
Private helper methodclass BankAccount(private var balance: Double) { fun deposit(amount: Double) { validateAmount(amount) balance += amount } private fun validateAmount(amount: Double) { require(amount > 0) { "Amount must be positive" } } fun getBalance() = balance }

6Inheritance

Inheritance lets a child class (subclass) inherit properties and methods from a parent class (superclass). In Kotlin, classes must be marked open to be inherited. Use : syntax instead of Java's extends.

Basic inheritanceopen class Vehicle(val brand: String, val speed: Int) { open fun move() { println("$brand moving at $speed km/h") } } class Car(brand: String, speed: Int, val doors: Int) : Vehicle(brand, speed) { override fun move() { println("Car $brand with $doors doors at $speed km/h") } } fun main() { Car("Honda", 120, 4).move() }

Calling superclass

super keywordopen class Base { open fun greet() = println("Hello from Base") } class Derived : Base() { override fun greet() { super.greet() println("Hello from Derived") } } fun main() { Derived().greet() }

Kotlin vs Java inheritance

FeatureKotlinJava
Extend classclass B : A()class B extends A
Implement interfaceclass B : A(), Iimplements I
Overrideoverride fun (required keyword)@Override annotation
Default finalClasses/methods final unless openExtendable unless final
Interfaces: Kotlin supports multiple interface inheritance — see Interfaces & Abstraction.

7Polymorphism

Polymorphism ("many forms") allows a variable of a parent type to refer to objects of different subclasses. The correct method implementation is chosen at runtime — dynamic dispatch.

Runtime polymorphismopen class Shape { open fun area(): Double = 0.0 } class Circle(val radius: Double) : Shape() { override fun area() = Math.PI * radius * radius } class Rectangle(val w: Double, val h: Double) : Shape() { override fun area() = w * h } fun printArea(shape: Shape) { println("Area: ${shape.area()}") } fun main() { val shapes: List<Shape> = listOf(Circle(5.0), Rectangle(4.0, 6.0)) shapes.forEach { printArea(it) } }

Polymorphism with when

Type checking and smart castfun describe(shape: Shape) { when (shape) { is Circle -> println("Circle r=${shape.radius}") is Rectangle -> println("Rectangle ${shape.w}x${shape.h}") else -> println("Unknown shape") } }

Types of polymorphism

TypeWhen resolvedKotlin example
Runtime (dynamic)At runtimeoverride fun on subclass
Compile-time (static)At compile timeOverloaded functions (same name, different params)
ParametricVia genericsList<T> — see Generics
Design tip

Program to interfaces or base classes — fun process(repo: Repository) works with any implementation without changing the caller.

8Encapsulation

Encapsulation hides internal state and exposes controlled access through public methods and properties. It protects data integrity and reduces coupling between components.

Encapsulated classclass BankAccount(private var balance: Double) { fun deposit(amount: Double) { if (amount <= 0) return balance += amount } fun withdraw(amount: Double): Boolean { if (amount <= 0 || amount > balance) return false balance -= amount return true } fun getBalance(): Double = balance } fun main() { val account = BankAccount(1000.0) account.deposit(500.0) account.withdraw(200.0) println("Balance: ${account.getBalance()}") // 1300.0 // account.balance — not accessible (private) }

Visibility modifiers

ModifierClass memberTop-level declaration
publicVisible everywhereVisible everywhere (default)
privateSame class onlySame file only
protectedClass + subclassesNot allowed at top level
internalSame moduleSame module

Benefits of encapsulation

Data protection

Private fields cannot be changed invalidly from outside the class.

Flexibility

Change internal implementation without breaking callers.

Validation

Setters and methods enforce rules (e.g. positive amounts only).

Abstraction

Expose only what clients need — hide complexity.

Protected property in inheritanceopen class BaseAccount(protected var balance: Double) class SavingsAccount(initial: Double) : BaseAccount(initial) { fun addInterest(rate: Double) { balance += balance * rate // protected — accessible in subclass } }
OOP pillars recap: Encapsulation + Inheritance + Polymorphism (+ Abstraction via interfaces) form the core of object-oriented design in Kotlin and Android architecture.

9Summary Cheatsheet

TopicKey Takeaway
Classesclass Name; no new; final by default
ObjectsSingleton, companion object, anonymous object
ConstructorsPrimary in header; secondary with : this(...); init blocks
Propertiesval/var; custom get/set; lateinit, lazy
MethodsMember functions; override for polymorphic behavior
Inheritanceopen class; class Child : Parent(); super
PolymorphismParent reference, child object; runtime dispatch via override
Encapsulationprivate/protected; controlled access via methods/properties
Next lessonInterfaces & Abstraction

Kotlin OOP MCQ Practice

10 Basic MCQs 10 Advanced MCQs

10 Basic Kotlin OOP MCQs

1

How do you declare a class in Kotlin?

Aclass Person
Bnew class Person
CPerson class
Ddefine Person
Explanation: See Kotlin OOP lesson — correct answer is A.
2

How do you create an instance of a class?

Anew Person()
BPerson() — no new keyword
Ccreate Person()
DPerson.new()
Explanation: See Kotlin OOP lesson — correct answer is A.
3

Which keyword makes a class inheritable?

Afinal
Bopen
Cpublic
Dstatic
Explanation: See Kotlin OOP lesson — correct answer is B.
4

Where is the primary constructor declared?

AIn a separate constructor block only
BIn the class header
CIn companion object
DIn init only
Explanation: See Kotlin OOP lesson — correct answer is A.
5

Properties in the primary constructor use?

AOnly var in body
Bval or var in the header
CNo parameters allowed
Dstatic fields
Explanation: See Kotlin OOP lesson — correct answer is B.
6

Which keyword overrides a parent method?

Aoverwrite
Boverride
Csuper
Dopen
Explanation: See Kotlin OOP lesson — correct answer is B.
7

Classes in Kotlin are by default?

Aopen to inheritance
Bfinal — need open to inherit
Cabstract
Dsealed
Explanation: See Kotlin OOP lesson — correct answer is A.
8

An abstract class can be?

AInstantiated directly
BExtended but not instantiated if abstract
COnly an interface
DA singleton
Explanation: See Kotlin OOP lesson — correct answer is A.
9

Polymorphism means?

AOne class only
BSame reference, different runtime behavior
CNo inheritance
DOnly private methods
Explanation: See Kotlin OOP lesson — correct answer is A.
10

Encapsulation hides?

APublic methods
BInternal state using access modifiers
CConstructors only
DPackages
Explanation: See Kotlin OOP lesson — correct answer is B.

10 Advanced Kotlin OOP MCQs

11

init blocks run when?

ABefore class definition
BWhen an instance is created
COnly on companion
DNever
Explanation: See Kotlin OOP lesson — correct answer is A.
12

Secondary constructors use?

Aconstructor keyword and delegate to primary
BOnly init
Cstatic factory only
Dnew keyword
Explanation: See Kotlin OOP lesson — correct answer is B.
13

super.method() calls?

AStatic parent
BParent class implementation
CInterface only
DCompanion object
Explanation: See Kotlin OOP lesson — correct answer is A.
14

Custom property getter syntax?

Aget value()
Bget() = computed
Cgetter always auto
Dfetch()
Explanation: See Kotlin OOP lesson — correct answer is B.
15

object keyword creates?

AMultiple instances
BA singleton instance
CAbstract class
DInterface
Explanation: See Kotlin OOP lesson — correct answer is A.
16

companion object is like?

AJava static members in a real object
BMultiple inheritance
CGlobal variable only
DSealed subclass
Explanation: See Kotlin OOP lesson — correct answer is B.
17

open fun in parent means?

ACannot override
BCan be overridden in subclass
CPrivate method
DInline only
Explanation: See Kotlin OOP lesson — correct answer is A.
18

Abstract fun has?

AFull body required
BNo body in abstract class
COnly in interfaces
DAlways static
Explanation: See Kotlin OOP lesson — correct answer is B.
19

Inheritance syntax?

Aextends Parent
B: Parent()
Cimplements Parent
Dinherits Parent
Explanation: See Kotlin OOP lesson — correct answer is A.
20

Member functions live?

AOnly top-level
BInside classes or objects
COnly in interfaces
DOnly companion
Explanation: See Kotlin OOP lesson — correct answer is A.
Click an option to select, then check answers.

Kotlin OOP Interview Q&A

15 topic-focused questions for interviews and revision.

1How do you declare a class in Kotlin?easy
Answer: Use class Name with optional primary constructor: class Person(val name: String). Create instances with Person("Alex") — no new keyword.
2What is the difference between val and var in a class?easy
Answer: val is read-only after init; var is mutable. Both can be properties with getters/setters.
3What is a primary constructor?easy
Answer: Declared in the class header: class User(val id: Int). It runs when the object is constructed; init blocks follow.
4What does open mean on a class?easy
Answer: The class can be subclassed. By default classes are final in Kotlin unlike Java.
5Explain inheritance in Kotlin.medium
Answer: class Dog : Animal() — single inheritance for classes. Override methods with override; mark parent methods open to allow override.
6What is polymorphism?medium
Answer: A variable of parent type can refer to subclass instances; calling an overridden method runs the subclass version at runtime.
7How does encapsulation work?medium
Answer: Use private or protected for internal state; expose behavior through public methods and properties with controlled access.
8What is an init block?medium
Answer: Code in init { } runs when an instance is created, after the primary constructor initializes properties.
9Difference between object and class?medium
Answer: class defines a blueprint for many instances. object declares a singleton — one instance created by the runtime.
10What is a companion object?medium
Answer: A singleton inside a class — like static members but is a real object; can implement interfaces and have a name.
11Secondary constructor example?hard
Answer: constructor(name: String) : this(name, 0) { } — must delegate to primary with this(...) or another secondary.
12How do property getters/setters work?hard
Answer: Custom get() and set(value) in the property body; field is implicit for simple backing storage.
13Why are Kotlin classes final by default?hard
Answer: Encourages composition over inheritance; use open explicitly when subclassing is intended — safer API design.
14Compare abstract class vs interface for OOP design.hard
Answer: Abstract class: shared state, constructors, single inheritance. Interface: contracts, default impls, multiple implementation.
15How does override differ from Java?hard
Answer: Both parent and child must participate — parent method open, child method override. Prevents accidental overrides.