摘自《快学Scala》
0.重点
- extends,final关键字和Java中相同
- 重写方法时必须用override
- 只有主构造器可以调用超类的主构造器
- 可以重写字段
- 本章只探讨类继承自另一个类的情况
1.扩展类
class Employee extends Person{
var salary = 0.0
}
和Java一样,将类声明为final
,就不能被扩展了。
2.重写方法
Scala中重写一个非抽象方法必须使用override修饰符。
public class Person{
...
override def toString = getClass.getName + "[name=" + name + "]"
}
override修饰符可以给出有用的错误提示
* 当你拼错了要重写的方法名
* 当你不小心在新方法中使用了错误的参数类型
* 当你在超类中引入了新的方法,而这个新方法与子类的方法相抵触】
Scala中调用超类的方法:super关键字。
public class Employee extends Person{
...
override def toString = super.toString + "[salary=" + salary + "]"
}
super.toString会调用超类的toString方法——即Person.toString
类型检查和转换
要测试某个对象是否属于某个给定的类,可以用isInstanceOf
方法。如果测试成功,就可以用asInstanceOf
方法将引用转换为子类的引用:
if (p.isInstanceOf[Employee]){
val s = p.asInstanceOf[Employee] //s的类型为Employee
}
// 如果你想要测试p指向的是一个Employee对象但又不是其子类,可以用:
if(p.getClass == classOf[Employee])
与类型检查和转换相比,模式匹配是更好的选择:
p match{
case s:Employee => ...
case _ => //p不是Employee
}
4.受保护字段和方法
同Java和C++一样,可以将字段或方法声明为protected
,这样的成员可以被任何子类访问,但不能从其他位置看到。
与Java不同,protected的成员对于类所属的包而言,是不可见的。
Scala还提供了一个protected[this]
的变体,将访问权限限定在当前对象。类似private[this]
.
5.超类的构造
6.重写字段
class Person(val name:String){
override def toString = getClass.getName + "[name= + name + "]"
}
class SecretAgent(codename:String) extends Person(codename){
override val name = "secret"
override val toString = "secret"
}
更常见的案例是用val重写抽象的def,就像这样:
abstract class Person{
def id:Int
...
}
class Student(override val id:Int) extends Person //学生id通过构造器输入
7.匿名子类
val alien = new Person("Fred"){
def greeting = "Greetings, Earthling! My name is Fred."
}
def meet(p:Person{def greeting:String}){
println(p.name + "says:" + p.greeting)
}
8.抽象类
和Java一样,可以用abstract关键字来标记不能被实例化的类,通常这是因为它的一个或几个方法没有被完整定义。例如:
abstract class Person(val name:String){
def id:Int //没有方法体,这是个抽象方法
}
如果某个类至少存在一个抽象方法,则该类必须声明为abstract。
在子类中写超类的抽象方法时,不需要使用override
关键字。
class Employee(name:String) extends Person(name){
def id = name.hashCode // 不需要override关键字
}
9.抽象字段
抽象字端就是一个没有初始值的字段。如:
abstract class Person{
val id:Int //没有初始化——这是一个带有抽象的getter方法的抽象字段
var name:String //另一个抽象字段,带有抽象的getter和setter方法
}
具体的子类必须提供具体的字段:
class Employee(val id:Int) extends Person{ //子类有具体的id属性
var name=""//和具体的name属性
}
可以随时用匿名类型来定制抽象字段:
val fred = new Person{
val id = 1729
var name = "Fred"
}
10.构造顺序和提前定义
class Creature{
val range:Int = 10
val env:Array[Int] = new Array[Int](range)
}
class Ant extends{
override val range = 2
}with Creature
提前定义的等号右侧只能引用之前已有的提前定义,而不能使用类中的其他字段或方法。