Composition and Inheritance
继承类或者抽象类时重写方法需要加上override关键字
实现trait里的方法可以不需要
class声明时直接在()里用val标记参数,可以直接生成对应的字段并被访问
无参数的方法
class A{
def method1={
}
def method2()={
}
}
method1是一个无参数方法
调用时直接 objA.method1即可
也可以 objA.method1()访问
method2只能通过objA.method2()访问
补充:上面的例子里不能再声明一个method1()的方法
无参数的mehtod和field共享同一个命名空间
不可以
class A{
val a=0;
def a={
}
}
val a和def a的区别在于
val a的值会直接存在内存里,def a则在每次调用时都会执行一遍,看具体需求进行选择
在继承时,父类是def a的子类可以写成override val a=xxx 反之亦然
对于class.method和class.method()写法的区别
书中建议是如果方法调用是没有side-effect的,即不会改变对象的状态,每次的返回值都相同,则使用class.method,反之,改变了状态,使用class.method()
注:print和println方法都应该带上(),他们改变了Console的状态
子类使用父类的构造方法在extends后面指明
final关键字同java
将具体实现的子类屏蔽在工厂类里
通过Companion Object作为工厂,返回具体类型,对client屏蔽子类
Scala’s Hierarchy
Any是所有类的根
声明了几个基本方法
final def ==(that: Any): Boolean
final def !=(that: Any): Boolean
def equals(that: Any): Boolean
def ##: Int
def hashCode: Int
def toString: String
基本的Int,Long,Double等继承自AnyVal
所有的普通类继承自AnyRef,AnyRef相当于是java.lang.Object的别名
Null和Nothing是所有类型的子类
Nothing用来在一些一定会抛出异常的方法的返回值
Trait
可以类似java的interface使用
所有方法都不实现,trait会被直接编译成java的interface
trait也可以实现一些方法,作为代码重用的基本单元,trait可以被多继承,也可以声明,但不能new
scala里有一个Ordered trait,里面实现了所有 > < <= >=等方法
如果自己实现的类需要进行比较,只需要继承Ordered,并实现它的 compare方法(返回值同java的Comparable.compare),就可以使用这些> <等之类的方法
Traits as stackable modifications
可以理解为通过trait实现的链式的装饰器模式
class A extends B with TraitA with TraitB
B必须是一个class
如果 A B TraitA TraitB里都声明并且实现了某个方法method,
且实现为附加操作以后调用super.method(...)
则调用的顺序是 A TraitB TraitA B
和extends后声明的顺序相反
如果A里面没有声明 则是TraitB TraitA B
对于下面的结构
class Animal
trait Furry extends Animal
trait HasLegs extends Animal
trait FourLegged extends HasLegs
class Cat extends Animal with Furry with FourLegged
对Cat类来说,调用顺序是
Cat - FourLegged - HasLegs - Furry -Animal (后面还有AnyRef,Any)
另,Trait中如果包含了方法实现,修改Trait需要重新编译该Trait的所有子类
所以对于作为lib要发布出去的类,谨慎使用Trait,一旦修改Trait,所有client的代码都要重新编译
Packages and Imports
可以按照java的方式声明package,
也可以如下
package bobsrockets {
package navigation {
// In package bobsrockets.navigation
class Navigator
package tests {
// In package bobsrockets.navigation.tests
class NavigatorSuite
}
}
}
编译器会自动处理,把编译好的class放到对应的文件夹中
对于上面方式声明的package和对象
NavigatorSuite里可以直接访问到上层package里的Navigator
但是如果分开到不同的文件里,则无法访问
访问同级别下的其他package里的类,可以简写
如包结构 a.b.c.d.e.f.g
在包d下面有个类D,包g下面有类G
在D里面可以直接用e.f.g.G访问,不需要a.b.c
G访问D,需要指明
_root_表示根的包
import package._
import package
new package.Class
也可以在方法体里面import某个类或者包
别名
import java.sql.{Date => SDate}
后面的只能通过SDate访问java.sql.Date
import Fruits.{Apple => McIntosh, _}
加载所有 Fruits下的类,但是Apple 重命名为McIntosh
import Fruits.{Apple => _, _}
加载所有Fruits下的类 除了Apple,区别在于第一个_
scala会默认加载3个包
import java.lang._ // everything in the java.lang package
import scala._ // everything in the scala package
import Predef._
access modifiers
scala里只有private 和 protected 没有则自动认为是public
protected同java
private和java的private有一点不同
一个类的字段是private,在java里是能被这个类的内部类访问到的
而scala是不能访问到,反过来是可以的
class Outer {
class Inner {
private def f() { println("f") }
class InnerMost {
f() // OK
}
}
(new Inner).f() // error: f is not accessible
}
只需要把private def f声明为 private[Outer] def f即可在Outer里访问到,具体说明如下
package bobsrockets
package navigation {
private[bobsrockets] class Navigator {
protected[navigation] def useStarChart() {}
class LegOfJourney {
private[Navigator] val distance = 100
}
private[this] var speed = 200
}
}
package launch {
import navigation._
object Vehicle {
private[launch] val guide = new Navigator
}
}
Table 13.1 · Effects of private qualifiers on LegOfJourney.distance
no access modifier public access
private[bobsrockets] access within outer package
private[navigation] same as package visibility in Java
private[Navigator] same as private in Java
private[LegOfJourney] same as private in Scala
private[this] access only from same object
private[]的声明在编译后的字节码里都是public,因此可能会存在一些问题
另:关于内部类和外部类这章里没有介绍,简单实验了下应该和java是一样的
不过静态内部类需要声明到companion object里面,即同名的object声明类里