面向对象之继承语法差异补齐
1 继承
- 和 Java 一样使用 extends 关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法。如果类声明为 final,他将不能被继承。如果单个方法声明为 final,将不能被重写。scala 明确规定,只要出现 override 情况,一定要显式声明关键字 override
1.1 重写方法
- 重写一个非抽象方法需要用 override 修饰符,调用超类的方法使用 super 关键字
object Scala02_Extends01 {
def main(args: Array[String]): Unit = {
val emp = new Emp01
emp.speak()
}
}
class Person01{
def speak()={
println("Perosn speak...")
}
}
class Emp01 extends Person01{
override def speak()={
println("Emp speak...")
}
}
运行结果:
Emp speak...
1.2 类型检查和转换
- 要测试某个对象是否属于某个给定的类,可以用 isInstanceOf 方法。用 asInstanceOf
方法将引用转换为子类的引用。 classOf 获取对象的类名。
- classOf[String]就如同 Java 的 String.class
- obj.isInstanceOf[T]就如同 Java 的 obj instanceof T
- obj.asInstanceOf[T]就如同 Java 的(T)obj
def main(args: Array[String]): Unit = {
val emp:Person01 = new Emp01
emp.speak()
testClass(emp)
}
def testClass(p : Person01)={
// if(p instanceOf Emp01){
// Emp01 e = (Emp01)p
// e.empno
// }else if(p instanceof Student01){
// Student01 s = (Student01) p
// s.stuno
// }
if(p.isInstanceOf[Emp01]){
val e = p.asInstanceOf[Emp01] //转成Emp01类型
println(classOf[Emp01]) // <==> Emp01.class e.getClass
println(e.empno)
}else if (p.isInstanceOf[Student01]){
val s = p.asInstanceOf[Student01]
println(classOf[Student01]) // <==> Emp01.class e.getClass
println(s.stuno)
}
}
运行结果:
Emp speak...
class com.nefu.scala.chaptor04.Emp01
E001
1.3 受保护的字段和方法
- protected 在 scala 中比 Java 要更严格一点,即, 只有继承关系才可以访问,同一个包下,也是不可以的。具体请参考:包可见性
1.4 超类的构造
类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须以对先前定义的辅助构造器或主构造器的调用开始。 子类的辅助构造器最终都会调用主构造器
def main(args: Array[String]): Unit = {
val emp:Person01 = new Emp01
// emp.speak()
// testClass(emp)
println(emp.personname)
}
class Emp01(empName:String="zhang4") extends Person01(empName){
var empno="E001"
override def speak()={
println("Emp speak...")
}
}
class Student01(stuName:String="li3") extends Person01(stuName){
var stuno = "S111"
}
1.5 覆写字段
- 子类改写父类的字段
class Person02(){
println("父类构造器")
val name = "zhangsan"
}
class Emp02 extends Person02{
override val name:String = "lisi"
}
1、 def 只能重写另一个 def
2、 val 只能重写另一个 val 或不带参数的 def
3、 var 只能重写另一个抽象的 var(声明未初始化的变量就是抽象的变量)
object Scala03_Extends02 {
def main(args: Array[String]): Unit = {
val emp = new Emp02
println(emp.name)
println(emp.age)
}
}
abstract class Person02(){
println("父类构造器")
//抽象属性:本质还是set和get方法抽象的原因
var age:Int
//val name = "zhangsan"
//def name = "zhang3"
def name():String = {
"zhang3"
}
}
class Emp02 extends Person02{
override val name:String = "lisi"
override var age:Int = 30
}
1.6 抽象类
- 可以通过 abstract 关键字标记不能被实例化的类。方法不用标记 abstract,只要省掉方法体即可。 抽象类可以拥有抽象字段,抽象字段就是没有初始值的字段。
abstract class Person02(){
println("父类构造器")
//抽象属性:本质还是set和get方法抽象的原因
var age:Int
//val name = "zhangsan"
def testMethod
//def name = "zhang3"
def name():String = {
"zhang3"
}
}
class Emp02 extends Person02{
override val name:String = "lisi"
var age:Int = 30
/**
* Java的多态是根据父子类继承关系实现的
* Java的接口是为了解决多继承问题
* Java的多态实现了向上转型
*/
def testMethod={
List list
}
}
- 注:子类重写抽象方法不需要 override
1.7 匿名子类
- 和 Java 一样,你可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类:
object Scala03_Extends02 {
def main(args: Array[String]): Unit = {
//val emp = new Emp02
//println(emp.name)
//println(emp.age)
val teacher = new Person02(){
override var age: Int = 50
override def testMethod: Unit = println(age)
}
teacher.testMethod
}
}
abstract class Person02(){
println("父类构造器")
//抽象属性:本质还是set和get方法抽象的原因
var age:Int
//val name = "zhangsan"
def testMethod
//def name = "zhang3"
def name():String = {
"zhang3"
}
}
运行结果:
父类构造器
50
1.8 构造顺序和提前定义
- 当子类重写了父类的方法或者字段后,父类又依赖这些字段或者方法初始化,这个时候就会出现问题
- 动态方法绑定技术:
public class Java_DynMethod {
public static void main(String[] args) {
//动态方法绑定技术
/**
* 方法和真实存在的内存地址进行绑定
* 属性不支持动态绑定
*/
A a = new B();
a.test();
//B对象动态绑定的test方法是A的test方法
// 但是属性不支持动态绑定,所以是A中的i属性作为参数
}
}
class A{
private int i = 10;
public void test(){
System.out.println(i + 10);
}
}
class B extends A{
private int i = 20;
// public void test(){
// System.out.println(i + 20);
// }
}
1.9 继承类型
- 在 scala 中,所有其他类都是 AnyRef 的子类,类似 Java 的 Object。
- AnyVal 和 AnyRef 都扩展自 Any 类。 Any 类是根节点
- Any 中定义了 isInstanceOf、 asInstanceOf 方法,以及哈希方法等。
- Null 类型的唯一实例就是 null 对象。可以将 null 赋值给任何引用,但不能赋值给值类型的变量。
- Nothing 类型没有实例。它对于泛型结构是有用处的,举例:空列表 Nil 的类型List[Nothing],它是 List[T]的子类型, T 可以是任何类。