This post contains a collection of examples of Scala classes and class properties. I created most of these in the process of writing the Scala Cookbook.
Unlike the Cookbook, I don’t describe them much here, I just show the examples, mostly as a reference for myself (and anyone else that can benefit from them).
Basic Scala class examples
# a basic class
class Person(var name: String, var age: Int)
# use the class
val al = new Person("Al", 42)
al.name // "Al"
al.age // 42
A bit more real-world:
// define the class
class Person(val firstName: String, val lastName: String) {
println("the constructor begins")
val fullName = firstName + " " + lastName
val HOME = System.getProperty("user.home");
// define some methods
def foo { println("foo") }
def printFullName {
// access the fullName field, which is created above
println(fullName)
}
printFullName
println("still in the constructor")
}
// demonstrate the class in the repl
scala> val p = new Person("Alvin", "Alexander")
the constructor begins
Alvin Alexander
still in the constructor
p: Person = Person@68f507d2
The visibility of class parameters
A look at the visibility of class parameters:
// 'name' is a var
class Person(var name: String)
val p = new Person("Alvin Alexander")
p.name // String = Alvin Alexander
p.name = "Fred Flintstone" // String = Fred Flintstone
// 'name' is a val
class Person(val name: String)
val p = new Person("Alvin Alexander")
p.name // String = Alvin Alexander
p.name = "Fred Flintstone" // error: reassignment to val
// 'name' is neither var or val
class Person(name: String)
val p = new Person("Alvin Alexander")
p.name // error: value name is not a member of Person
// 'name' is 'private var'
class Person(private var name: String) { def printName {println(name)} }
val p = new Person("Alvin Alexander")
p.name // error: variable name in class Person cannot be accessed in Person
p.printName // Alvin Alexander
What var, val, and default mean when applied to class parameters:
Declaration Getter? Setter? ----------- ------- ------- var yes yes val yes no default no no
Auxiliary constructors
Define auxiliary constructors using this as the name for each auxiliary constructor. Make sure you call a previously defined constructor:
class Pizza {
var crustSize = 12
var crustType = "Thin"
def this(crustSize: Int) {
this()
this.crustSize = crustSize
}
def this(crustSize: Int, crustType: String) {
this(crustSize)
this.crustType = crustType
}
override def toString = {
"A %s inch pizza with %s crust.".format(crustSize, crustType)
}
}
That class defines three constructors, which can be called like this:
object AuxiliaryConstructors extends App {
println(new Pizza)
println(new Pizza(14))
println(new Pizza(16, "Thick"))
}
Running this object results in the following output:
A 12 inch pizza with Thin crust. A 14 inch pizza with Thin crust. A 16 inch pizza with Thick crust.
Private constructor
A simple way to enforce the Singleton pattern in Scala is to make the primary constructor private, then put a getInstance method in the companion object of the class:
class Brain private {
override def toString = "This is the brain."
}
object Brain {
val brain = new Brain
def getInstance: Brain = {
brain
}
}
object SingletonTest extends App {
// this won't work
// val brain = new Brain
// this works
val brain = Brain.getInstance
println(brain)
}
Default values for constructor parameters
You can provide default values for constructor parameters:
class Socket (var timeout: Int = 10000) // create instance without a param, get the default value val s = new Socket s.timeout // Int = 10000 // specify your own timeout value val s = new Socket(5000) s.timeout // Int = 5000
When to use an abstract class
Why use an “abstract class”? It can have constructor parameters, but a trait cannot.
Traits don’t allow constructor parameters:
// this won't compile trait Animal(name: String) // so use an abstract class abstract class Animal(name: String)
In the following example the methods save, update, and delete are defined in the abstract class BaseController, and the method connect is undefined, and therefore abstract:
abstract class BaseController(db: Database) {
def save { db.save }
def update { db.update }
def delete { db.delete }
def connect // abstract since it has no implementation
def getStatus: String // an abstract method that returns a String
def setServerName(serverName: String) // an abstract method that takes a parameter
}
JavaBean classes
To create JavaBean classes, use the @BeanProperty annotation on your fields, also making sure to declare the fields as the type var. The @BeanProperty annotation can be used in a constructor:
import scala.reflect.BeanProperty
class Person(@BeanProperty var firstName: String,
@BeanProperty var lastName: String,
@BeanProperty var age: Int) {
// more code here ...
}
It can also be used on fields in a class:
import scala.reflect.BeanProperty
class EmailAccount {
@BeanProperty var accountName: String = null
@BeanProperty var username: String = null
@BeanProperty var password: String = null
@BeanProperty var mailbox: String = null
@BeanProperty var imapServerUrl: String = null
@BeanProperty var minutesBetweenChecks: Int = 0
@BeanProperty var protocol: String = null
@BeanProperty var usersOfInterest = new java.util.ArrayList[String]()
}
Scala case classes
You can generate a lot of useful boilerplate code with a case class:
case class Person(var name: String, var age: Int)
With the special case class incantation, Scala generates a great deal of code for you:
- toString, equals, and hashCode methods.
- The constructor parameters you specify become properties with getters and setters.
- You no longer have to use ’new’ to create an instance of your class.
- You can use convenient extractors in match/case statements.
To see the code that Scala generates for you, first compile a simple class, then disassemble it with javap. First, put this code in a file named Person.scala:
case class Person(var name: String, var age: Int)
Then compile the file:
$ scalac Person.scala
This creates two class files, Person.class and Person$.class. Disassemble Person.class to see its signature:
$ javap Person
Compiled from "Person.scala"
public class Person extends java.lang.Object implements scala.ScalaObject,scala.Product,scala.Serializable{
public static final scala.Function1 tupled();
public static final scala.Function1 curry();
public static final scala.Function1 curried();
public scala.collection.Iterator productIterator();
public scala.collection.Iterator productElements();
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
public Person copy(java.lang.String, int);
public int copy$default$2();
public java.lang.String copy$default$1();
public int hashCode();
public java.lang.String toString();
public boolean equals(java.lang.Object);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public boolean canEqual(java.lang.Object);
public Person(java.lang.String, int);
}
Also disassemble Person$.class to see its signature:
$ javap Person$
Compiled from "Person.scala"
public final class Person$ extends scala.runtime.AbstractFunction2 implements scala.ScalaObject,scala.Serializable{
public static final Person$ MODULE$;
public static {};
public final java.lang.String toString();
public scala.Option unapply(Person);
public Person apply(java.lang.String, int);
public java.lang.Object readResolve();
public java.lang.Object apply(java.lang.Object, java.lang.Object);
}
The protected keyword
The protected keyword:
- the protected keyword in scala has a different meaning than in java
- protected means current class and subclasses can access member
- unlike java, other classes in package can’t access member
Example:
package foo {
class Foo {
// (1) make 'getFoo' protected.
protected def getFoo = "foo"
}
class FooSub extends Foo {
def doFoo = {
// (2) we can access getFoo because we're a subclass of Foo
val x = getFoo
}
}
class Bar {
def doBar = {
val f = new Foo
// (3) this line won't compile because getFoo is protected
//f.getFoo
}
}
}
package baz {
import foo.Foo
class Baz {
def doBaz = {
val f = new Foo
// (4) this won't work either
//f.getFoo
}
}
}
| this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
Summary
In summary, I hope these Scala class examples have been helpful. I’ll keep adding more to these examples as time goes on.