欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

scala notes (2) - Class, Object, Package & Import and Inheritance

程序员文章站 2022-05-03 13:09:14
...

- Class

class Counter {
    private var value = 0 // You must initialize the field, otherwise it's abstract class.
    def increment() { value += 1 } // Methods are public by default
    def current() = value
}
class Person {
    var age = 0 // private age field, public set and get methods. if its val, private final field and only get method generated
}

  • object-private field -> private[this] var value = 0
  • Bean Property
class Person {
    @BeanProperty var name: String = _ //generate two more methods, getName and setName
}

class Person(@BeanProperty var name: String)
  • Primary Constructor & Auxiliary Constructor
class Person(val name: String = "", val age: Int = 0)
class Person private(val name: String = "", val age: Int = 0) //private primary constructor

primary constructor executes all statements in class definition

class Person {
    private var name = ""
    private var age = 0
    def this(name: String) { // An auxiliary constructor
        this() // Calls primary constructor
        this.name = name
    }
}

auxiliary constructor needs to call previously defined constructor before its own construction.

class Person(name: String, age: Int) { //
    def description = s"$name is $age years old" //generate private[this] fields of name and age
}
class Person(name: String, age: Int){
    println(s"$name is $age years old") //no fields generated
}
  • nested classes
import scala.collection.mutable.ArrayBuffer
class Network {
    class Member(val name: String) {
        val contacts = new ArrayBuffer[Member]
    }
}

val n1 = new Network; val n2 = new Network;  n1.Member is different from n2.Member

solution is,

put class Member definition to Network companion object 

or 

use type projection, Network#Member


- Objects

  • no parameter constructor of object
  • good for utility functions or constants
  • class and its companion object must be in the same source file. They can access each other's private features.
class Account {
    val id = Account.newUniqueNumber()
    private var balance = 0.0
    def deposit(amount: Double) { balance += amount }
    ...
}
object Account { // The companion object
    private var lastNumber = 0
    private def newUniqueNumber() = { lastNumber += 1; lastNumber }
}

  • object extends class or trait 
abstract class UndoableAction(val description: String) {
    def undo(): Unit
    def redo(): Unit
}

object DoNothingAction extends UndoableAction("Do nothing") {
    override def undo() {}
    override def redo() {}
}
  • Enum (Enumeration)
object TrafficLightColor extends Enumeration {
    val Red, Yellow, Green = Value
}
for (c <- TrafficLightColor.values) println(s"${c.id}: $c")

TrafficLightColor(0) // Calls Enumeration.apply
TrafficLightColor.withName("Red")



- Packages & Imports

  • same package can be in different source files.
  • one source file can have multiple packages
  • scope rules
package com {
    package horstmann {
        object Utils {
            def percentOf(value: Double, rate: Double) = value * rate / 100
            ...
        }
        package impatient {
            class Employee {
                ...
                def giveRaise(rate: scala.Double) {
                    salary += Utils.percentOf(salary, rate) //parent package horstmann and ancestor package com are in scope
                }
            }
        }
    }
}
package path is not absolute in scala, use _root_.yourpackagepath

chained package is not visible, 

package com.horstmann.impatient {
    // Members of com and com.horstmann are not visible here
    package people {
        class Person
        ...
    }
}
  • package object (functions can be put inside too)
package com.horstmann.impatient
    package object people {
        val defaultName = "John Q. Public"
    }
    package people {
        class Person {
            var name = defaultName // A constant from the package
        }
        ...
    }
  • package visibility
package com.horstmann.impatient.people
class Person {
    private[people] def description = s"A person with name $name"
    or 
    private[impatient] def description = s"A person with name $name"
    ...
}

==========imports===========

  • import java.awt._  
  • import java.awt.Color._
  • import statement can be anywhere
class Manager {
    import scala.collection.mutable._
    val subordinates = new ArrayBuffer[Employee]
    ...
}
  • import java.awt.{Color, Font} // selection
  • import java.util.{HashMap => JavaHashMap} // rename
  • import java.util.{HashMap => _, _} // import everything except HashMap
  • Implicit Imports
import java.lang._
import scala._
import Predef._
StringBuilder is overridden by scala


- Inheritance

class Employee extends Person {
    var salary = 0.0
    ...
}
  • override keyword to override non-abstract method
class Person {
    ...
    override def toString = s"${getClass.getName}[name=$name]"
}
  • call superclass method, super
  • isInstanceOf, asInstanceOf, classOf
  • protected variable cannot be visited by classes or objects under the same package. it can only be accessed from subclass. protected[this]
  • only primary constructor can call super class constructor
class Employee(name: String, age: Int, val salary : Double) extends Person(name, age)
  • override field/method
class Person(val name: String) {
    override def toString = s"${getClass.getName}[name=$name]"
}
class SecretAgent(codename: String) extends Person(codename) {
    override val name = "secret" // val override field
    override val toString = "secret" //val override method
}
abstract class Person { // See Section 8.8 for abstract classes
    def id: Int // Each person has an ID that is computed in some way
    ...
}
class Student(val id: Int) extends Person
// A student ID is simply provided in the constructor
• A def can only override another def.
• A val can only override another val or a parameterless def.

• A var can only override an abstract var

  • anonymous subclass
val alien = new Person("Fred") {
    def greeting = "Greetings, Earthling! My name is Fred."
}

alien is object of structural type, Person{def greeting: String}

def meet(p: Person{def greeting: String}) {
    println(s"${p.name} says: ${p.greeting}")
}
  • Construction Order
class Creature {
    val range: Int = 10
    val env: Array[Int] = new Array[Int](range) // range is getter method
}

class Ant extends Creature {
    override val range = 2
}

problem is env will be a empty array when new object of Ant due to range is overridden in Ant. 

Thus, you should not rely on the value of a val in the body of a constructor.

Remedy is early definition.

class Ant extends { override val range = 2 } with Creature

  • inheritance hierarchy

scala notes (2) - Class, Object, Package &amp;amp;amp; Import and Inheritance

Any -> isInstanceOf, asInstanceOf, equal and hashcode, ==(final), !=(final), toString, ##

AnyRef -> wait, notify/notifyAll, synchronized , eq (reference equality)

Null has sole instance null which can only be set to AnyRef classes

Nothing has no instance. used in generic construct, like Nil has type List[Nothing]

not implemented method with type Nothing

class Person(val name: String) {
    def description = ???
}
def error(message: String): Nothing = //error method can be used as return of any return type
    throw new RuntimeException(message) 

Unit has sole value ().

def printAny(x: Any) { println(x) }
def printUnit(x: Unit) { println(x) }
printAny("Hello") // Prints Hello
printUnit("Hello")
// Replaces "Hello" with () and calls printUnit(()), which prints ()

def show(o: Any) { println(s"${o.getClass}: $o") } //Any or AnyRef
show(3) // Prints class java.lang.Integer: 3
show(3, 4, 5) // Prints class scala.Tuple3: (3,4,5)

  • Object Equality

default equals calls eq to compare references. 

final override def equals(other: Any) = {//parameter is Any, change hashcode too.
    other.isInstanceOf[Item] && {
        val that = other.asInstanceOf[Item]
        description == that.description && price == that.price
    }
}
final override def hashCode = (description, price).## //combine hashcodes of the two

== calls equals method for reference type.

  • Value classe
1. The class extends AnyVal.
2. Its primary constructor has exactly one parameter, which is a val, and no body.
3. The class has no other fields or constructors.
4. The automatically provided equals and hashCode methods compare and hash the
underlying value.
class MilTime(val time: Int) extends AnyVal {
    def minutes = time % 100
    def hours = time / 100
    override def toString = f"$time04d"
}