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"
}
Concept
Kotlin
Java equivalent
Declare class
class Name { }
class Name { }
Create instance
val obj = Name()
Name obj = new Name();
Default visibility
public (implicit)
public (implicit)
Inheritance default
Classes are final by default
Classes 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()
}
Keyword
Purpose
Instances
object Name { }
Singleton
Exactly one
companion object
Factory methods, constants
One per class
object : Type { }
Anonymous implementation
Created 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")
}
Constructor
Syntax
Notes
Primary
class X(val a: Int)
One per class; can have default values
Secondary
constructor(...) : this(...)
Must delegate to primary with this
init block
init { }
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)
Keyword
Use case
val
Read-only property (getter only)
var
Mutable property (getter + setter)
field
Reference backing field in custom getter/setter
lateinit var
Non-null var initialized after construction
by lazy
Computed 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
Modifier
Visible from
public
Everywhere (default)
private
Same class only
protected
Class and subclasses
internal
Same 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()
}
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
Type
When resolved
Kotlin example
Runtime (dynamic)
At runtime
override fun on subclass
Compile-time (static)
At compile time
Overloaded functions (same name, different params)
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
Modifier
Class member
Top-level declaration
public
Visible everywhere
Visible everywhere (default)
private
Same class only
Same file only
protected
Class + subclasses
Not allowed at top level
internal
Same module
Same 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
Topic
Key Takeaway
Classes
class Name; no new; final by default
Objects
Singleton, companion object, anonymous object
Constructors
Primary in header; secondary with : this(...); init blocks
Properties
val/var; custom get/set; lateinit, lazy
Methods
Member functions; override for polymorphic behavior
Inheritance
open class; class Child : Parent(); super
Polymorphism
Parent reference, child object; runtime dispatch via override
Encapsulation
private/protected; controlled access via methods/properties