Raffi Khatchadourian (based on “Scala for the Impatient” 2nd Edition by Cay Horstmann)
September 22, 2020
extends
and final
keywords are similar to those in Java.override
keyword when you override a method.
@Override
annotation in Java.class Person(val name: String) {
override def toString = s"${getClass.getName}[name=$name]"
}
val p = new Person("Juan")
println(p)
Outputs:
Person[name=Juan]
protected
.Recall that a field in Scala consists of:
You can override a val
(or parameterless def
) with another val
field of the same name.
Then, the subclass will have a private field and a public accessor, which overrides the one from the super class.
class Person(val name: String) {
override def toString = s"${getClass.getName}[name=$name]"
}
class SecretAgent(codename: String) extends Person(codename) {
override val name = "secret"
override def toString = "shh"
}
val s = new SecretAgent("1234")
println(s)
Outputs:
shh
Can also override an abstract def
with a val
:
abstract class Person {
def id: Int // No implementataion, specific to each kind of person.
// ...
}
/**
* A concrete implementation of Person.
*/
class Student(override val id: Int) extends Person {
// The student ID is supplied by the ctor.
// ...
override def toString = s"Student with ID: ${id}"
}
val s = new Student("54321")
println(s)
Outputs:
Student with ID: 54321
override
keyword not required when providing an implementation for an abstract method.
Can also have abstract fields, i.e., fields without an initial value:
abstract class Person {
val id: Int // No initializer---abstract field and accessor.
var name: String // No initializer---abstract field, accessor, and mutator.
// ...
}
class Employee(val id: Int) extends Person { // Has a concrete id property.
var name = "John Doe" // and a concrete name property that can be concretized.
override def toString = s"Employee ${name} with ID: ${id}"
}
val e = new Employee(5)
println(e)
Outputs:
Employee John Doe with ID: 5
What if we did not override name
? What would happen?
Unit
, i.e., ()
, extend AnyVal
.
AnyVal
has no methods; it’s just “marker.”AnyRef
.
java.lang.Object
.Any
is the hierarchy root. It defines:
isInstanceOf[]
asInstanceOf[]
ScalaObject
.Null
is a singleton type with the value null
.
null
to any reference.Nothing
has no instances.Scala inheritance hierarchy diagram
Nothing
Useful for generic constructs.
Nil
has the type List[Nothing]
.List[T]
for any T
.The method ???
has return type Nothing
.
NotImplementedErr
.class Person(val name: String) {
def speak() {println(s"My name is ${name}.")}
def description = ???
}
val p = new Person("Sofia")
p.speak() // OK!
println(p.description)
Outputs:
My name is Sofia.
scala.NotImplementedError: an implementation is missing ...
The eq
method of AnyRef
checks whether two references refer to the same object.
The equals
method in AnyRef
calls eq
.
When designing your own classes, consider overriding equals
method:
Item
objects may be “equal” if they have the same description and price.name
fields are equal, do the references refer to the same object?
equals
method unless there is some other unique identifier.If you do override equals
, you must also override hashCode
:
##
method is a null-safe version of the hashCode
method.
null
instead of throwing an exception.Don’t call eq
or equal
from application code. Instead, use ==
, which, for reference types, checks for null
and calls equals
.
A value class:
AnyVal
.val
) parameter, i.e., the “wrapped” value, and no body.equals
and hashCode
methods that simply delegate to the wrapped value.