Programming in Scala 2nd 读书笔记 3

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声明类里


你可能感兴趣的:(scala,FP)