Functional Object
Advantages and Disadvantages of Immutable Object
Adv 1. 不可变对象更具容易被推断出来,因为它不会随着时间的变化而造成值的变化。
Adv 2. 不可变对象可以自动地传递不会发生变化,而传递可变对象的话,需要首先对可变对象进行备份,以防止在其它过程中对对象的状态造成了修改。
Adv 3. 线程不能够更改(corrupt:腐化,堕落)不可变对象的状态,注定他是线程安全的。
Adv 4. 不可变对象拥有安全的Hashtable的key值。对于一个可变对象而言,如果在把这个对象存放到一个HashSet中之后,对象的值发生了变化,那么再次在这个HashSet中寻找这个对象是找不到的。
DisAdv: 有时需要创建好多个不可变对象,尤其是当需要对这个对象的状态进行修改的时候。并且,这样可能会产生效率问题。
1 构造器(Constructor)
scala的构造器跟类的声明是放在一起的,class Rational(n: Int, d:Int)
但是这样一个单独的构造器是没有什么意义的,因为除了构造一个对象之外,别无它用
除非我们使用到了他的构造器中的参数,才会有意义的构造器存在(class文件中)。
Scala compiler会把scala文件中所有的,不存在于方法中的,非声明字段的语句放到这个scala对象的构造器中。
一些字段的声明字段会按照顺序在主构造器中赋值。。。
2 toString方法重新实现(override)
java.lang.Object 中的方法toString()会被所有的java对象,包括scala对象继承。
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
返回String为类名@十六进制的哈希值,useless!!!
重写之(in scala way):
override def toString = "Rational : " n + "/" + d + " was created."
3 先决条件检查Precondition Check
as long as we know that the denominator of some rational can not be 0, any else int will be acceptable.
so we should make sure of this.
require(expression...)
require is a method defined in standalong object Predef which will imported in implicitly.
有两种形式的require方法:
def require(requirement: Boolean) { if (!requirement) throw new IllegalArgumentException("requirement failed") }
和
@inline final def require(requirement: Boolean, message: => Any) { if (!requirement) throw new IllegalArgumentException("requirement failed: "+ message) }
看这个方法,应该是有多少个限定条件就应该有多少个require,除非仅有一条错误消息。
4 Add Method
如果想要创建不可变对象,那么就不要尝试改变这个对象,而只应该去创建新的对象。
you can only access their value on the object on which add was invoked
只能够获得方法的调用者的对象的域,而方法的参数对象的域则不能够访问到。
其实这就是相当于,一个private的属性,在别的类里面是没有办法访问到的。
为了让外界获取,可以通过追加一个field,让这个field等于构造函数参数的值。
如:val numerator = n
这样一来,会在class文件中,
1 追加一个private final int = numerator;
2 构造函数中,给numerator赋值为n的值;
3 追加一个名称为numerator的public方法,返回值为numerator;
5 self reference
The keyword this refers to the object instance on which the currently executing method was invoked, or if used in a constructor, the object instance being constructed.
this这个关键字引用的是调用当前方法的对象,或者是,构造中的对象(用在构造方法中的时候)。
this还可以用来指代构造函数。。。
通常情况下,this.是可以省略的,而当要返回当前对象的时候this就显得尤其重要,没他不行!!!
6 auxiliary constructor scala的叫法,从构造器
从构造器都是以def this(...)的形式来书写的
如: def this(n:Int) = this(n, 1)
scala中,从构造器必须要首先调用一个别的构造器
7 private method and field
%,返回余数,没有问题。
12和15的最大公倍数(greatest common divisor)跟15和12的最大公倍数是一回事儿。
也就是说,在球最大公倍数的方法中,应该让他们能够转换。
12%15 = 12
15%12 = 3
15%12 = 3
12%3 = 0
3%0 就没啥意思了
def gcd(a:Int, b:Int):Int = if (b==0) a else gcd(b, a%b)
8 identifier in scala, scala标示符
1 字母数字标识符,以字母或者下划线开头,后面可以为任意字符。然而$符也算是一个字符,他可以作为方法使用,但是可能会出现问题,所以避免使用。
1 camel-case驼峰形变量名或者方法名,下划线式儿的也行,但是scala不怎么用这种
2 下划线结尾的字段声明的时候,要跟后面的:之间追加一个空格,否则会认为下划线后面的冒号也是变量名的一部分
3 常量的标示符也是camel-case的,只不过首字母大写,这是scala的方式
2 操作符标识符:operator identifier
+ ++ ::: <?> :-> 这些都是合理的标示符,只不过这些标示符会被翻译成$加上一些colon,minus等形成一个java能够调用的方法
:-> 将被翻译成 $colon$minus$greater,scala能够调用:->,而java只能够调用$colon$minus$greater方法
3 混合标识符:mixed identifier
unary_+
4 文本标识符:literal identifier
`something`
在Java的Thread类中访问静态的yield方法是其典型的用例。你不能写Thread.yield()因为yield是Scala的保留字。然而,你仍可以在反引号里引用方法的名称,例如Thread.`yield`()。
9 implicit conversion 隐式转换
如果想让一个类中的方法同样适用于另外一个类的对象,且这两个类之间可以按照某些方式转换,那么隐式转换将非常有用
2 + new Rational(1, 2)
肯定不能执行,因为+的操作数不可能是一个Rational类型的。。。
但是我们可以把2转换成一个Rational,这是比较先进的。。。
在app里面追加如下方法即可实现:
implicit def intToRational(i:Int) = new Rational(i)
并且这个方法的转换是只能的,只有在需要的时候才会发生这个转换。
如果我们在这个方法的后面追加
println(2 + 2),他并不会去隐式转换,因为它会发现这个2 + 2它能够处理。
Programming In Scala Reading Note 5