Copyright © Cay S. Horstmann 2015
val now = new java.util.Date // and not java.sql.Date
package com { package horstmann { package impatient { class Employee ... } } }Fully qualified name:
com.horstmann.impatient.Employee
package com.horstmann.impatientLike in Java: The entire source file is in this package.
import java.util.Date val now = new Date // shortcut for new java.util.Date
import java.util._ import java.lang.Math._ // like import static in Java
import java.awt.{Color, Font} // import two classes import java.util.{HashMap => JavaHashMap} // alias import java.util.{HashMap => _, _} // hide a class
class Manager { import scala.collection.mutable._ val subordinates = new ArrayBuffer[Employee] ... }
java.lang
, scala
, Predef
are always imported.java.util
and java.util.regex
.package com { package horstmann { object App { def run { ... } } package impatient { new App(...) } } }
App
could be com.horstmann.App
or scala.App
._root_.scala.App
to disambiguate.class Manager extends Employee
e.isInstanceOf[Manager] // like e instanceof Manager e.asInstanceOf[Manager] // like (Manager) e e.getClass == classOf[Manager] // like Manager.class
class Employee(name: String, age: Int, val salary: Double) extends Person(name, age)
class Employee extends Person with Cloneable with Serializable
class ArrayBuffer[A] extends AbstractBuffer[A] with Buffer[A] with GenericTraversableTemplate[A, ArrayBuffer] with BufferLike[A, ArrayBuffer[A]] with IndexedSeqOptimized[A, ArrayBuffer[A]] with Builder[A, ArrayBuffer[A]] with ResizableArray[A] with CustomParallelizable[A, ParArray[A]] with Serializable
trait Logged { def log(msg: String) {} } trait ConsoleLogger extends Logged { override def log(msg: String) { println(msg) } } class SavingsAccount extends Logged { private var balance: Double = 0 def withdraw(amount: Double) { if (amount > balance) log("Insufficient funds") else balance -= amount } // ... } val acct = new SavingsAccount with ConsoleLogger val acct2 = new SavingsAccount with FileLogger
trait TimestampLogger extends Logged { override def log(msg: String) { super.log(new java.util.Date() + " " + msg) } } trait ShortLogger extends Logged { val maxLength = 15 override def log(msg: String) { super.log( if (msg.length <= maxLength) msg else msg.substring(0, maxLength - 3) + "...") } } val acct1 = new SavingsAccount with ConsoleLogger with TimestampLogger with ShortLogger acct1.withdraw(1000) // Sun Nov 01 17:45:45 ICT 2015 Insufficient...
java.awt.Rectangle
class has a method translate
that moves a rectangle by a given amount. Try it out: In a worksheet, import the java.awt
package, construct a new Rectangle(5, 10, 20, 30)
, call translate(10, 20)
, and see what its coordinates are now.java.awt.geom.Ellipse2D.Double
. Make an instance val egg = new geom.Ellipse2D.Double(5, 10, 20, 30)
. Why didn't you have to put java.awt
before geom
?egg.translate(10, 20)
. What happens?Ellipse2D
, or better, its superclass RectangularShape
? We can fix that in Scala. Define a trait:
trait RectangleLike { def setFrame(x: Double, y: Double, w: Double, h: Double): Unit def getX: Double def getY: Double def getWidth: Double def getHeight: Double def translate(dx: Double, dy: Double) { setFrame(getX + dx, getY + dy, getWidth, getHeight) } }Now change the definition of
egg
so that the call to translate
works. What did you do?val acct2 = new SavingsAccount with ConsoleLogger with ShortLogger with TimestampLogger { override val maxLength = 20 }Without running the program, what do you think will happen when you call
acct2.withdraw(1000)?
val acct3 = new SavingsAccount with ShortLogger with TimestampLogger with ConsoleLogger
java.io
library, one has to work hard to get services such as buffering:
new BufferedReader(new InputStreamReader(new FileInputStream("/usr/share/dict/words")))It shouldn't be so hard to add buffering. (Buffering means not to read each byte separately but to read them a chunk at a time.) Here is a Scala trait:
trait Buffered extends InputStream { val SIZE = 1024 private var end = 0 private val buffer = new Array[Byte](SIZE) private var pos = 0 override def read() = { if (pos == end) { end = super.read(buffer, 0, SIZE) pos = 0 } if (pos == end) -1 else { pos += 1 buffer(pos - 1) } } }Mix in
Buffered
into a new FileInputStream("/usr/share/dict/words")
(or some other file if you aren't running Linux/Mac OS). How do you do that? Then call read
a few times. What do you get?