Object-oriented programming helps you model real concepts in code. In Android apps, you might model a User, Course, Lesson, Payment, or Notification.
Classes And Objects
A class is a blueprint. An object is a real instance created from that blueprint.
class Course(
val title: String,
val lessonCount: Int
) {
fun description(): String {
return "$title has $lessonCount lessons"
}
}
val course = Course("Junior Android Developer", 22)
println(course.description())
Data Classes
Use data class for objects that mainly hold data.
data class Lesson(
val title: String,
val durationMinutes: Int,
val completed: Boolean
)
Kotlin automatically gives data classes useful behavior like copy, equals, and readable toString.
val lesson = Lesson("Kotlin Basics", 30, false)
val completedLesson = lesson.copy(completed = true)
Encapsulation
Encapsulation means keeping internal details private and exposing only what other code needs.
class ProgressTracker {
private var completed = 0
fun markDone() {
completed++
}
fun currentProgress(): Int = completed
}
This prevents random parts of your app from changing progress incorrectly.
Inheritance
Inheritance lets one class reuse behavior from another, but use it carefully. Kotlin classes are final by default. You must mark a class open to allow inheritance.
open class Animal {
open fun speak() = "sound"
}
class Dog : Animal() {
override fun speak() = "bark"
}
In Android, composition is often preferred over deep inheritance. Instead of making huge base classes, inject dependencies and keep components small.
Interfaces
An interface defines a contract: a list of functions a class must implement.
interface UserRepository {
suspend fun getUser(id: String): User
suspend fun saveUser(user: User)
}
A class can then implement that contract:
class RemoteUserRepository(private val api: UserApi) : UserRepository {
override suspend fun getUser(id: String) = api.fetchUser(id)
override suspend fun saveUser(user: User) = api.updateUser(user)
}
Interfaces matter in Android because they let you swap implementations. In tests, you swap the real repository for a fake one. In production, you use the real one. The ViewModel never needs to know the difference.
Objects and Companion Objects
An object creates a single instance — a singleton.
object AnalyticsLogger {
fun log(event: String) {
println("Event: $event")
}
}
AnalyticsLogger.log("screen_viewed")
A companion object belongs to a class and is accessed on the class itself, not an instance.
class UserRepository {
companion object {
const val MAX_CACHE_SIZE = 100
}
}
println(UserRepository.MAX_CACHE_SIZE)
You will see companion objects used for constants, factory functions, and log tags.
Practice
Create a Student data class with name, completedLessons, and totalLessons. Add a function that returns whether the student has completed the course.
Summary
Classes model behavior and data. Data classes are perfect for app state and API models. Interfaces define contracts for swappable implementations. Objects and companion objects provide single instances and constants. Inheritance exists, but beginner Android developers should prefer simple composition and clear data models.