← Scala EnglishChapter 07 of 13

Classes

## Learning Objectives - Master class definitions - Work with constructors - Understand companion objects - Learn case classes - Master basic OOP concepts in Scala ## Class Basics ### Defining a Class ```scala class Person { var name: String = "" var age: Int = 0 def greet(): String = s"Hello, I'm $name" } val person = new Person() person.name = "Alice" person.age = 30 println(person.greet()) // Hello, I'm Alice ``` ### Primary Constructor The class parameters become the primary constructor: ```scala class Person(val name: String, var age: Int) { def greet(): String = s"Hello, I'm $name" } val alice = new Person("Alice", 30) println(alice.name) // Alice println(alice.age) // 30 alice.age = 31 // OK - var // alice.name = "Bob" // Error - val ``` ### Constructor with Default Values ```scala class Person(val name: String = "Unknown", var age: Int = 0) { def greet(): String = s"Hello, I'm $name" } val unknown = new Person() // name="Unknown", age=0 val bob = new Person("Bob") // name="Bob", age=0 val alice = new Person("Alice", 30) // name="Alice", age=30 ``` ## Auxiliary Constructors ```scala class Person(val name: String, var age: Int) { def this(name: String) = this(name, 0) // Auxiliary constructor def this() = this("Unknown", 0) // Another auxiliary override def toString = s"Person($name, $age)" } val p1 = new Person("Alice", 30) val p2 = new Person("Bob") val p3 = new Person() ``` ## Visibility Modifiers ### Private Members ```scala class BankAccount(private var balance: Double) { def deposit(amount: Double): Unit = { if (amount > 0) balance += amount } def withdraw(amount: Double): Boolean = { if (amount > 0 && amount <= balance) { balance -= amount true } else { false } } def getBalance: Double = balance // Getter } val account = new BankAccount(100) account.deposit(50) account.withdraw(30) println(account.getBalance) // 120 // account.balance // Error: balance is private ``` ### getter and setter Generation ```scala class Person { var name: String = _ // Generates getter and setter val id: Int = 0 // Generates getter only private var balance: Double = 0 // No getter/setter generated private[this] var secret: String = "" // Object-private } ``` ## Companion Objects A companion object has the same name as the class: ```scala class Person(val name: String, val age: Int) { override def toString = s"Person($name, $age)" } object Person { def apply(name: String, age: Int): Person = new Person(name, age) def apply(name: String): Person = new Person(name, 0) def createStudent(name: String, age: Int): Person = { if (age < 0) throw new IllegalArgumentException("Invalid age") new Person(name, age) } } // Using companion val p1 = Person("Alice", 30) // apply method val p2 = Person("Bob") // apply with default age val p3 = Person.createStudent("Charlie", 25) ``` ## Case Classes Case classes automatically generate: - val parameters (immutable fields) - apply, unapply, copy methods - toString, equals, hashCode ```scala case class Person(name: String, age: Int) { def greet(): String = s"Hello, I'm $name" } val alice = Person("Alice", 30) // No 'new' needed - apply is generated val bob = Person("Bob", 25) // Immutable - no var allowed by default // alice.age = 31 // Error! // Copy with modifications val aliceOlder = alice.copy(age = 31) // Pattern matching alice match { case Person(n, a) => s"$n is $a years old" } // Equality val alice2 = Person("Alice", 30) alice == alice2 // true (equals generated) // Hash map usage val people = Set(alice, alice2) // Set contains only one Person("Alice", 30) ``` ## Objects Objects are singleton instances: ```scala object Config { val defaultTimeout = 30 val maxRetries = 3 def getSetting(key: String): String = { // Load from config key match { case "timeout" => defaultTimeout.toString case "retries" => maxRetries.toString case _ => "unknown" } } } println(Config.defaultTimeout) // 30 println(Config.getSetting("timeout")) // 30 ``` ## Class vs Object vs Case Class | Feature | Class | Object | Case Class | |---------|-------|--------|------------| | Instantiation | new | Single instance | new (or apply) | | Parameters | var/val | N/A | val by default | | Methods | Yes | Yes | Yes | | extends | Yes | Yes | Yes | | equals/hashCode | Reference | N/A | Generated | | apply | Not generated | Yes | Generated | | unapply | Not generated | Yes | Generated | | copy | Not generated | N/A | Generated | ## Abstract Classes ```scala abstract class Shape { def area(): Double def perimeter(): Double } class Circle(val radius: Double) extends Shape { def area(): Double = Math.PI * radius * radius def perimeter(): Double = 2 * Math.PI * radius } class Rectangle(val width: Double, val height: Double) extends Shape { def area(): Double = width * height def perimeter(): Double = 2 * (width + height) } ``` ## Nested Classes ```scala class Outer { class Inner { def hello() = "Hello from Inner" } def createInner(): Inner = new Inner() } val outer = new Outer() val inner = outer.createInner() println(inner.hello()) ``` ## Enum-like Structures ```scala object Color extends Enumeration { val Red = Value val Green = Value val Blue = Value val Yellow = Value("YELLOW") } import Color._ Red match { case Red => "Red" case Green => "Green" case Blue => "Blue" case _ => "Other" } ``` ## Summary - Classes define blueprints; objects are singleton instances - Primary constructor parameters can be val or var - Private members hide implementation details - Companion objects provide factory methods and static-like utilities - Case classes automatically generate boilerplate for immutable data - Case class copy creates modified copies - Abstract classes define contracts for subclasses - Use objects for utility functions and singleton state

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →