What a class is
A class is a blueprint for objects. It says what data each object holds (its fields) and what each object can do (its methods). An object, also called an instance, is one concrete thing built from that blueprint, with actual values: not the idea of an employee, but an employee named Andrew who is 30.
The simplest class has a name and an empty body:
class Employee {
}
Creating objects
You create an instance by calling the class like a function. Scala 3 allows this without new, and new Employee still works too:
val employee = Employee()
val other = new Employee
Each call makes a separate object with its own state.
Fields
A field is a variable that belongs to an object. You declare it in the class body and read or change it with the dot operator:
class Employee {
var name: String = ""
var age: Int = 0
}
val emp1 = Employee()
emp1.name = "Andrew"
val emp2 = Employee()
emp2.age = 40
Every instance has its own copy of the fields. Setting emp1.name does not touch emp2.name, which is still the empty string. Use var for a field that can change and val for one that is set once.
Constructors
You usually want to give an object its values when you create it. In Scala, the constructor parameters go right in the class header:
class Employee(var name: String, var age: Int) {
}
val emp1 = Employee("Andrew", 30)
println(emp1.name) // Andrew
The words var and val in front of a parameter do real work. With var, the parameter also becomes a public, changeable field. With val, it becomes a public read-only field. With neither, it is only a constructor parameter that the class's own methods can use, and code outside can't reach it as a field. Writing Employee("Mary", 25).name works with var or val in the header, but is a compile error without either.
Methods
A method is a function defined inside the class. It uses def, a name, parameters and a return type. A method that returns nothing useful has the return type Unit. Inside the class, a method can use the fields by name:
class Employee(var name: String, var age: Int) {
def printName(): Unit = {
println(name)
}
def printEmployee(): Unit = {
printName()
println(age)
}
}
val emp = Employee("Andrew", 30)
emp.printEmployee() // prints Andrew, then 30
You call a method with the dot, as you read a field. The call uses the fields of the object it is called on, so emp.printEmployee() prints Andrew's details, and a second employee prints hers.
The word this
Inside a method, this is the object the method was called on. You rarely need it, because name already means this.name. It matters when a parameter has the same name as a field:
class Person(var name: String) {
def rename(name: String): Unit = {
this.name = name // field on the left, parameter on the right
}
}
Common mistakes
- Leaving out
varorvalin the constructor. The parameter is then private to the class, and outside code can't read it. - Assigning to a
valfield. If a field is declared withval, code likejob.id = 2fails to compile withReassignment to val. - Forgetting that objects are references. After
val j2 = j1, both names point to the same object, so changingj2.titlealso changesj1.title. - Calling a method on the class instead of an object. Methods run on an instance, so create one first.
The lesson's exercise
The exercise defines a class named Job with a title and a method that announces a hire, and uses it from the Solution class.
- Above
Solution, declareclass Job(var title: String). The header declares and stores the title in one line. - Inside
Job, definedef hireMe(): Unit, a method with no parameters whose result type isUnit. - In its body, print
"You're hired as a "followed bytitle, joined with+. The field is used directly, withoutthis. - In
mainFunction, createval job = Job("Software Engineer"). - Call
job.hireMe().
The full solution:
class Job(var title: String) {
def hireMe(): Unit = {
println("You're hired as a " + title)
}
}
class Solution {
def mainFunction(): Unit = {
val job = Job("Software Engineer")
job.hireMe()
}
}
Calling mainFunction() on a Solution prints You're hired as a Software Engineer. The variable job is a val, but that only fixes which object it refers to. The object's own var field could still be changed.
Key takeaways
- A class is a blueprint; each object created from it has its own field values.
- Put the constructor parameters in the header, and add
varorvalto make them fields. - Methods are declared with
def, andUnitis the return type for "nothing useful". - Read fields and call methods with the dot; Scala 3 lets you create objects without
new.
