7:Package && Import
7.1 Packages
a:定义包语句 ,例如:
Java代码
- package com {
- package horstmann {
- package impatient {
- class Employee
- ...
- }
- }
- }
b: 一个包可以定义在多个文件中,例如Employee.scala /Manager.scala中
f: 并不强制将源文件放在 指定的包路径下
g:一个源文件按中可以定于多个包路径,例如:
Java代码
- package com {
- package horstmann {
- package impatient {
- class Employee
- ...
- }
- }
- }
- package org {
- package bigjava {
- class Counter
- ...
- }
- }
7.2 scope 范围规则
a: 例如:
Java代码
- 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)
- }
- }
- }
- }
- }
- Employee 所在的源文件 能够访问 com.* com.horstmann.* ,com.horstmannn.impatient 等parent 包中文件
b:scala 以及java.lang 是默认导入的,例如:
Java代码
- package com {
- package horstmann {
- package impatient {
- class Manager {
- val subordinates = new collection.mutable.ArrayBuffer[Employee]
- ...
- }
- }
- }
- }
- collection.mutable.ArrayBuffer 相当与scala.collection.mutable.ArrayBuffer
但是如果在嵌套类中 定义类以scala.java,com,org 等开头的包,则会导致 Manager 编译不了
例如 下面 的Manager 会编译不了
Java代码
- package com {
- package horstmann {
- package impatient {
- class Manager {
- val subordinates = new collection.mutable.ArrayBuffer[Employee]
- ...
- }
- }
- }
- }
- package com {
- package horstmann {
- package collection {
- ...
- }
- }
- }
c:Chained 包
例如:
Java代码
- package com.horstmann.impatient {
- // Members of com and com.horstmann are not visible here
- package people {
- class Person
- ...
- }
- }
- 其中 com com.horstmann 对于people 包来说是不可见的
d:放在文件头(通常使用方式)
例如:
Java代码
- package com.horstmann.impatient
- package people
- class Person {
- }
- 该方式等同于:
- package com.horstmann.impatient {
- package people {
- class Person
- ...
- // Until the end of the file
- }
- }
在上述定义的文件中所有东西都属于Person 类
7.5 Package Object
a:在JVM 中有package.class 文件,该类中定义了静态方法和字段
b:在scala中 可以定义 package.scala文件 用来 定义在该包中 的函数和方法
例如: com/horstmann/impatient/people/package.scala
c:包对象 如何定义:
Java代码
- package com.horstmann.impatient
- package object people {
- val defaultName = "John Q. Public"
- }
7.6 Package 可见性
a:一个class member 如果没有定义public,private or protected ,那么这个member 可以被 同一个包里的其他类给访问到
例如:下面这个方法就在自己的包里可见
Java代码
- class Person {
- private[people] def description = "A person with name " + name
- ...
- }
7.7 Import 语句
a: 导入一个类
Java代码
- 例如:
- import java.awt.Color
b:导入一个包下的所有类
例如:
Java代码
- import java.awt.Color._
- val c1 = RED // Color.RED
- val c2 = decode("#ff0000") // Color.decode
c:在任何地方导入:
例如:
Java代码
- class Manager {
- import scala.collection.mutable._
- val subordinates = new ArrayBuffer[Employee]
- ...
- }
7.8 重命名或者隐藏成员
a:导入包里几个Member
例如:
Java代码
- import java.awt.{Color, Font}
b:对成员重命名:
Java代码
- import java.util.{HashMap => JavaHashMap}
- import scala.collection.mutable._
- 结果为: JavaHashMap 对应为 java.util.HashMap
- HashMap 对应为 scala.collection.mutable.HashMap
c:隐藏成员
import java.util.{HashMap => _, _}
import scala.collection.mutable._
结果为 java.util.HashMap 被隐藏
HashMap 唯一对应 scala.collection.mutable.HashMap
7.9 隐式导入
a:每个scala 程序隐式导入:
Java代码
- import java.lang._
- import scala._
- import Predef._
b: scala 中和 java.lang. 中同名的对象 则会覆盖java.lang._中的同名对象
例如:
scala.StringBuilder 会覆盖 java.lang.StringBuilder
c:Predef 包含了许多有用的函数
8.继承
8.1 继承一个class
a:使用extends 继承class
b:可以在子类中添加新的字段和复写父类方法
c:可以将子类定义成final,以避免被继承
d:和java 中不同的是,可以将 方法和字段定义为 final
8.2 复写方法
a:使用 override 复写 父类中某个非abstract 方法、
a1:检查复写的方法名是否正确
a2:检查复写的方法的参数类型以及个数是否正确
b:使用super 调用父类方法
8.3 类型检查和转换
a:obj.isInstanceOf[ClassName] :测试Obj 是否指向className 类的对象
b:val s=obj.asInstanceOf[ClassName]: 将obj 引用转化为ClassName 子类的对象的引用
c:测试一个obj 指向的一个类的对象而不是子类的对象,则可以使用
p.getClass == classOf[ClassName]
q:类型检查和转化使用模式匹配:
例如:
Java代码
- p match {
- case s: Employee => ... // Process s as a Employee
- case _ => ... // p wasn’t a Employee
- }
8.4 protected 字段和方法
a:在scala 中,protected 修饰的字段和方法 从整个package到他们所属于的类都是不可见的。
b:protected[this]以及private[this] 限制了只能访问自己这个对象
8.5 超类构造函数
a:辅助类够找函数从来不会直接调用超类构造函数
b:只有主要构造函数能够直接调用超类构造函数。
c:主要构造函数和类的定义交织在一起,超类构造函数也和类的定义交织载一起,例如:
Java代码
- class Employee(name: String, age: Int, val salary : Double) extends
- Person(name, age)
d:一个scala 类可以继承 一个java 类。该scala 类必须要调用 父类java 中的一个构造函数
8.6 Override Fields
a:Override val field ,父类也需要具有同名的字段,
造成的效果 : 子类中有一个私有的字段 同时具有一个getter 方法,该方法复写了父类的getter 方法
b: Override val :也可以复写父类中没有参数的方法
例如:
Java代码
- 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(override val id: Int) extends Person
c:Override Def:
对于定义的方法,则会复写父类的方法
对于var,则需要同时复写getter 以及setter 方法
对于val, 则子类需要一个私有的字段以及复写getter 方法
d:Override var:
只有在超类中的var 是abstract, 在子类中才能用override var 进行该变量的复写
8.7 匿名类
如果在{} 一个快中使用了override 或者 def ,就定义了一个匿名类。
例如:
Java代码
- val alien = new Person("Fred") {
- def greeting = "Greetings, Earthling! My name is Fred."
- }
- 技术上: 这创造了一个新的Type,Person{def greeting: String},该类型可以这样使用:
- def meet(p: Person{def greeting: String}) {
- println(p.name + " says: " + p.greeting)
- }
8.8 抽象类
a:使用abstract 关键字来描述一个类不能被实例化
b:一个方法没有方法体,则该方法就是抽象的,和java 不一样,不需要在方法上强制使用abstract 关键字
c:对于定义为abstract 的方法,在子类的实现中可以不需要加上 override 关键词。
8.9: 抽象字段
a:没有初始值的字段为抽象字段
例如:
Java代码
- abstract class Person {
- val id: Int
- // No initializer—this is an abstract field with an abstract getter method
- var name: String
- // Another abstract field, with abstract getter and setter methods
- }
b:在子类实现时,必须提供抽象字段的具体值。和抽象方法一样,在子类中并不需要加上override 关键字
c:使用匿名类型,实现抽象字段,例如:
Java代码
- val fred = new Person {
- val id = 1729
- var name = "Fred"
- }
8.10:构造顺序和早期定义
使用场景: 在子类中复写了一个常量值,但是该常量值却用在了父类中, 在这种情况下输出的结果是未知的。
例如:
Java代码
- class Creature {
- val range: Int = 10
- val env: Array[Int] = new Array[Int](range)
- }
- class Ant extends Creature {
- override val range = 2
- }
- a:创造一个Ant 对象 则会 先调用Creature的构造函数
- b:Creature 对象 先将range 设置为10
- 接着为了初始化Array,则会调用get range 方法 也就是 range() 方法
- 由于子类Ant 复写了range 方法,则会调用子类的range方法 ,但是由于Ant 类还没有完成够找,因此 range 没有不赋值成2,因此range() 方法返回的是0。
- 因此Creature 生成的ent 数组的长度既不是10 也不是2,而是一个长度为0的数组
如何解决上述问题? 解决方法
a:将range 定义成 final val
b:将range 设置的lazy val 在父类中
c:载子类中使用,early definition syntax 语法,例如:
Java代码
- class Bug extends {
- override val range = 3
- } with Creature
8.11 scala 类的继承图
a:java 中的原始类型以及 Unit ,则继承AnyVal
b:其他类都是AnyRef 的子类
c;AnyRef 以及AnyVal 都是Any 的子类
d:Any 方法定义了 isInstanceOf, asInstanceOf, equal,hashCode
e:AnyVal 没有添加任何方法
f:AnyRef 添加了 wait,notify notifyAll ,synchronized方法
g:所有的scala 类都实现于ScalaObject 这个接口
h:NULL 类型,可以将null 赋值给任何引用,但是不能赋值给常量
i:Nothing类型没有实例,在用作范型的时候特别有用,例如 list Nill 的类型为List<Nothing>,是List[T]的子类型
具体如下图表示:
[/img]
8.12 equals 以及hashcode 方法
a:复写equals 方法,其中参数类型必须为other:Any
Java代码
- final override def equals(other: Any) = {
- val that = other.asInstanceOf[Item]
- if (that == null) false
- else description == that.description && price == that.price
- }
b:在应用程序中,我们一般建议使用 ==,该操作对于引用类型会先进行非空判断然后在调用equals方法