本章要点:
- extends,final关键字
- 重写方法用override
- 只有主构造器可以调用超类的主构造器
- 可以重写字段
(1)重写方法必须和被重写方法具有相同的参数列表,返回类型必须和被重写方法的返回类型相同或者是返回类型的子类型。
(2)重写方法的访问控制修饰符不能比被重写方法更严格(比如一个在父类中声明为public的方法重写成一个protected的方法)。
(3)只有实例方法才能被重写,超类中的final方法不能被重写。
(4)重写方法不能抛出新的检查异常,或者是抛出比被重写方法声明的检查异常更广泛的检查异常。
(5)注意一种特殊情况:如果超类的方法版本中声明了检查异常,但重写的子类方法中没有声明,这时如果使用多态的方式进行调用,那么编译器认为你调用的是声明了异常的方法。
(6)尽管多态是在编译时确定对象的类型,但在编译时,还是根据父类的方法声明进行程序检查。因此,如果子类中定义的方法,在父类中没有定义,则会出项编译错误。
3、类型检查和转换
要检测某个对象是否属于某个给定的类,可以用isInstanceOf方法。如果测试成功,可以用asInstanceOf方法将引用转换为子类的引用:
如果想要测试p是指向一个Employee对象,但又不是其子类的话,可以用:
if(p.getClass==classOf[Employee] )
4、受保护字段和方法
字段和方法声明为protected后可以被任何子类访问,但不能从其它位置看到。与java不同,protected的成员对于类所属的包而言是不可见的,如果需要可见,使用包修饰符。
protected[this]将访问权限限定在当前的对象,类似第5章的private[this]
访问修饰符的介绍:http://www.runoob.com/scala/scala-access-modifiers.html
5、超类的构造
6、重写字段
看不懂
7、匿名子类
匿名内部类也就是没有名字的内部类,正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码的编写。
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。
abstract
class
Person {
public
abstract
void
eat();
}
class
Child
extends
Person {
public
void
eat() {
System.out.println(
"eat something"
);
}
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Child();
p.eat();
}
}
运行结果:eat something
可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用
但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?这个时候就引入了匿名内部类。
abstract
class
Person {
public
abstract
void
eat();
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Person() {
public
void
eat() {
System.out.println(
"eat something"
);
}
};
p.eat();
}
}
可以看到,我们直接将抽象类Person中的方法在大括号中实现了,这样便可以省略一个类的书写而且匿名内部类还能用于接口上。
由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现 最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口。 |
10、构造顺序和提前定义
- 将val声明为final,安全但并不灵活
- 在超类中将val声明为lazy,安全但并不高效
- 在子类中使用提前定义语法