Scala的基本语法(五):面向对象高级

五 、面向对象高级

把一类事物的共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。

在Scala中创建对象的几种方式
  1. new 对象

  2. applay 方法,创建对象

  3. 动态混入

  4. 匿名子类创建对象

封装

​ 封装(encapsulation)就是把抽象出的数据/属性和对数据的操作/方法封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作


继承

​ 继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(比如Student),在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends语句来声明继承父类即可。

Scala继承给编程带来的便利
  1. 代码的复用性提高了
  2. 码的扩展性和维护性提高了【面试官问:当我们修改父类时,对应的子类就会继承相应的方法和属性】

重写:

  • override 在父类新方法跟子类冲突时能提供警告

  • Java中只有方法的重写,没有属性/字段的重写,准确的讲,是隐藏字段代替了重写

  • 重写字段的三个注意点

    • def只能重写另一个def(即:方法只能重写另一个方法)
    • val只能重写另一个val 属性 或 重写不带参数的def
    • var只能重写另一个抽象的var属性
  • 字段重写的本质是variable variable.__方法的重写,适用Java动态绑定机制,如果要访问覆写的父类字段,需要在父类自定义方法。

    override 不能重写父类@BeanProperty **var **的属性(var只能重写另一个抽象的var属性)但可以重写父类@BeanProperty **val **的属性,所以子类重写父类的属性后:

    ​ 要想父类属性既能读取又能改写,必须手动定义 类似gettersetter方法,

    ​ 只想父类属性可以读不能改写 ,用 override@BeanProperty val variable

    重写字段导致方法重写的情况(本质还是方法重写方法)

    class A {
       def sal(): Int = {   //底层是  private final int sal = 1; public int sal() { return 10}
          return 10
      }}
    class B extends A {
     override val sal : Int = 1 // 底层也是public int sal() { return this.sal} 
    }
    
     def main(args: Array[String]): Unit = {
        val b = new B
        println(b.sal) // 调用的是sal() 得到1
        val a=new A
        println(a.sal)// 调用的也是方法sal()得到10
        if(b.isInstanceOf[A]){
        val c=b.asInstanceOf[A]
        println(c.sal)} //多态使用bsal()得到1
      }
    
动态绑定机制
  • 当调用对象方法的时候,该方法会和该对象的内存地址绑定

  • 当对象调用属性时,没有动态绑定机制,在哪里调用,就返回哪里的值

    class A { //A是父类  A a = new B();10;
        public int sum() {
         return getI() + 10;  //子类继承且未重写sum(),因为i的getter方法子类也有,所有绑定子类的getter方法 返回子类i值
        }
    	public int sum1() {
            return i + 10;    //此处i是属性 在父类方法里调用 返回父类i的值
        }
    

抽象属性、类

抽象属性:没有初始化的属性,只能存在于抽象类中。由于底层是两个抽象的variable variable.__方法,所以子类val 或var实现的时候可以不写override。

继承过程

  • 子类继承了所有的属性(通过方法),只是私有的属性不能直接访问,需要通过公共的方法去访问。
  • 继承的关键看权限。与java一样,子类可以继承父类的所有,但不一定都能访问。看修饰方法是否public,scala中protect 同包下及子类可以访问,scala中protect修饰的内容无论如何只能自己或子类访问,虽然底层方法是public,但编译器会禁止在其他地方使用
  • 与java不同,在Scala的构造器中,子类无法调用super(params) ,只能用空参的,只有主构造器可以调用父类的构造器。辅助构造器不能直接调用父类的构造器。

类型检查和转换

​ 要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。用asInstanceOf方法将引用转换为子类的引用。classOf获取对象的类名。

if(p.isInstanceOf[Employee]) //如果p是Employee类或Employee的子类
vla s =p.asinstanceOf[Employee] //
if(p.getClass==classof[Employee]

多态

超类与java区别

  • 类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用)

​ 这个主要涉及到java里面一个字段隐藏的概念,父类和子类定义了一个同名的字段,不会报错。但对于同一个对象,用父类的引用去取值(字段),会取到父类的字段的值,用子类的引用去取值(字段),则取到子类字段的值。在实际的开发中,要尽量避免子类和父类使用相同的字段名,否则很容易引入一些不容易发现的bug。

类型投影

抽象类

  1. 抽象类不能被实例
  2. 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
  3. 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为abstract
  4. 抽象方法不能有主体,不允许使用abstract修饰。
  5. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法和抽象属性,除非它自己也声明为abstract类。
  6. 抽象方法和抽象属性不能使用private、final 来修饰,因为这些关键字都是和重写/实现相违背的。
  7. 抽象类中可以有实现的方法.
  8. 子类重写抽象方法不需要override,写上也不会错
  • 抽象类本身不能直接实例化但可以动态混入

伴生对象

  • 可用伴生对象创建匿名对象
  • Spark中定义用来设置常量类
原文地址:https://www.cnblogs.com/successok/p/14737326.html