• 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中定义用来设置常量类
  • 相关阅读:
    java大数取余
    hdu--5351--MZL's Border
    NYOJ--水池数目
    NYOJ--32--SEARCH--组合数
    NYOJ--20--搜索(dfs)--吝啬的国度
    hdu--4148--Length of S(n)
    hdu--2098--分拆素数和
    hdu--1873--看病要排队
    hdu--1870--愚人节的礼物
    hdu--1237--简单计算器
  • 原文地址:https://www.cnblogs.com/successok/p/14737326.html
Copyright © 2020-2023  润新知