Scala(自学-6)

目录

六、面向对象编程

c、方法的定义方式

d、封装

e、访问权限

f、对象

e、构造器

g、继承和多态

h、apply 方法

i、特质

j、扩展


 

六、面向对象编程

c、方法的定义方式

在Scala语言中,方法参数前不能加val和var关键字来进行限定,所有的方法参数都是不可变类型,相当于隐式地使用了val关键字限定,如果在方法体里面给参数重新赋值,将不能通过编译。对于无参数地方法,定义时可以省略括号,不过需要注意,如果定义时省略括号,那么调用的时候也不能带有括号;如果无参数方法在定义时带有括号,则调用时可以带括号,也可以不带括号。在调用方法时,方法后面的圆括号()可以用{}代替。另外,如果方法只有一个参数,可以省略.号而采用中缀操作符调用方法,形式为“调用者 方法名 参数”。列如,现在对上面定义的Counter类进行改写 。具体代码如下:

class Counter {
var value = 0
def increment (step:Int):Unit = {value += step}
def current:Int = value
def getValue():Int = value
}

在这种定义下,对current方法的调用不能带括号,对getVlue的调用可带也可以不带括号。

d、封装

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

  1. 将属性进行私有化
  2. 提供一个公共的 set 方法,用于对属性赋值
  3. 提供一个公共的 get 方法,用于获取属性的值

e、访问权限

在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通 过类似的修饰符达到同样的效果。但是使用上有区别。

  1. Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。
  2. private 为私有权限,只在类的内部和伴生对象中可用。
  3. protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以 访问,同包无法访问。
  4. private[包名]增加包访问权限,包名下的其他类也可以使用

f、对象

Scala类中没有Java那样的静态成员。Scala采用单例对象来实现于JAVA静态成员同样的功能。单例对象的定义与类定义类似,只是用object关键字替换了class关键字。

  1. 单例对象采用 object 关键字声明
  2. 单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
  3. 单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
object Person {
    private var lastId = 0
    def newPersonId() = {
        lastId +=1
        lastId    
}
}

有了这个单例对象,就可以直接通过其名字使用它,就像使用一个普通的类实例一样。

e、构造器

在Scala中,整个类定义主体就是类的构造器,称为主构造器,所有位于类方法以外的语句都将在构造过程中被执行。可以像定义方法参数一样,在类名之后用圆括号列出主构造器的参数列表。Scala类的构造器包括:主构造器和辅助构造器。

  1. 基本语法
    class 类名(形参列表) { // 主构造器
     // 类体
     def this(形参列表) { // 辅助构造器
     }
     def this(形参列表) { //辅助构造器可以有多个...
     }
    }
    

    辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型 来区分;辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法;构造器调用其他另外的构造器,要求被调用构造器必须提前声明;

  2. 构造器参数

Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰

  1. 未用任何修饰符修饰,这个参数就是一个局部变量
  2. var 修饰参数,作为类的成员属性使用,可以修改
  3. val 修饰参数,作为类只读属性使用,不能修改

g、继承和多态

  1. 基本语法
    1. val 修饰参数,作为类只读属性使用,不能修改
    2. 子类继承父类的属性和方法
    3. scala 是单继承
    4. 继承的调用顺序:父类构造器->子类构造器
  2. 动态绑定
    1. Scala 中属性和方法都是动态绑定,而 Java 中只有方法为动态绑定。
  3. 抽象类
    1. 基本语法

如果一个类包含没有实现的成员,则必须使用abtract关键字进行修饰,定义为抽象类。没有实现成员是指没有初始化的字段或者没有实现的方法。

abstract class Car{val name:String) {
    val carSrand:String //字段没有初始化值,就是一个抽象字段
    def cc() //抽象方法
    def dd() {
        println("Hello")
    }
}

抽象类中的抽象字段必须要有声明类型。与Java不同的是,Scala里的抽象方法不需要加abstract修饰符。抽象类不能进行实例化,只能作为父类或子类被其他子类继承。

                2. 继承&重写

像Java一样,Scala只支持单一继承,而不支持多重继承,即子类只能有一个父类。在类定义中用extends关键字表示继承关系。定义子类时,需要注意以下几个方面:

  1. 重写父类的抽象成员(包括字段和方法)时,override关键字是可选的;而重写父类非抽象的成员时,override关键字是必选的。建议在重写抽象成员是省略override关键字。这样做的好处是,如果随着业务的进展,父类的抽象成员被实现而成为非抽象成员时,子类相应成员由于没有override关键字,会出现编译错误,使用户能及时发现父类的改变,而如果子类成员原来就有override关键字,则不会有任何提醒。
  2. 只能重写val类型的字段,而不能重写var类型的字段。因为var类型本身就是可变的,所以,可以直接修改它的值,无需重写。
  3. 对于父类的主构造器中用var或val修饰的参数,由于其相当于类的一个字段,因此,如果子类的主构造器与父类的主构造器有相修饰名称的参数,则必须在子类的参数前加override修饰符,或者在子类的相同名称参数前去掉val或var,使其不自动成为子类的字段。
  4. 子类构造器必须调用父类的主构造器,所采用的方法是在extends关键字后的父类名称后跟上相应的参数列表,其中的参数个数和类型必须与父类的主构造器或者某个构造器一致。子类的辅助构造器不能调用父类的构造器。

h、apply 方法

  1. 说明
    1. 通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。
    2. 如果想让主构造器变成私有的,可以在()之前加上 private。
    3. apply 方法可以重载。
    4. Scala 中 obj(arg)的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg)。用 以统一面向对象编程和函数式编程的风格。
    5. 当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构 建对象时,调用的其实时伴生对象的 apply 方法。
      object Test {
       def main(args: Array[String]): Unit = {
       //(1)通过伴生对象的 apply 方法,实现不使用 new 关键字创建对象。
       val p1 = Person()
       println("p1.name=" + p1.name)
       val p2 = Person("bobo")
       println("p2.name=" + p2.name)
       }
      }
      //(2)如果想让主构造器变成私有的,可以在()之前加上 private
      class Person private(cName: String) {
       var name: String = cName
      }
      object Person {
       def apply(): Person = {
       println("apply 空参被调用")
       new Person("xx")
       }
       def apply(name: String): Person = {
       println("apply 有参被调用")
       new Person(name)
      }
      }

i、特质

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素, 所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父类,那么需要采用 with 关键字连接。

  1. 特质声明基本语法
    trait 特质名 {
    trait 主体
    }

  2. 特质基本语法

    1. 没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …

    2. 有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3…

  3. 说明

    1. 类和特质的关系:使用继承的关系。

    2. 当一个类去继承特质时,第一个连接词是 extends,后面是 with。

    3. 如果一个类在同时继承特质和父类时,应当把父类写在 extends 后。

    4. 特质可以同时拥有抽象方法和具体方法

    5. 一个类可以混入(mixin)多个特质

    6. 所有的 Java 接口都可以当做 Scala 特质使用

    7. 动态混入:可灵活的扩展类的功能

      1. 动态混入:创建对象时混入 trait,而无需使类混入该 trait

      2. 如果混入的 trait 中有未实现的方法,则需要实现

        trait PersonTrait {
         //(1)特质可以同时拥有抽象方法和具体方法
         // 声明属性
         var name: String = _
         // 抽象属性
         var age: Int
         // 声明方法
         def eat(): Unit = {
         println("eat")
         }
         // 抽象方法
         def say(): Unit
        }
        trait SexTrait {
         var sex: String
        }
        //(2)一个类可以实现/继承多个特质
        //(3)所有的 Java 接口都可以当做 Scala 特质使用
        class Teacher extends PersonTrait with java.io.Serializable {
         override def say(): Unit = {
         println("say")
         }
         override var age: Int = _
        }
        object TestTrait {
         def main(args: Array[String]): Unit = {
         val teacher = new Teacher
         teacher.say()
         teacher.eat()
         //(4)动态混入:可灵活的扩展类的功能
         val t2 = new Teacher with SexTrait {
         override var sex: String = "男"
         }
         //调用混入 trait 的属性
         println(t2.sex)
         }
        }
        

        特质和抽象类的区别:

        1. 优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。

        2. 如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数, 而特质不行(有无参构造)。

j、扩展

  1. 说明
    1. obj.isInstanceOf[T]:判断 obj 是不是 T 类型。
    2. obj.asInstanceOf[T]:将 obj 强转成 T 类型。
    3. classOf 获取对象的类名。
  2. 枚举类和应用类
    1. 枚举类:需要继承 Enumeration
    2. 应用类:需要继承 App
      object Test {
       def main(args: Array[String]): Unit = {
       println(Color.RED)
       }
      }
      // 枚举类
      object Color extends Enumeration {
       val RED = Value(1, "red")
       val YELLOW = Value(2, "yellow")
       val BLUE = Value(3, "blue")
      }
      // 应用类
      object Test20 extends App {
       println("xxxxxxxxxxx");
      }

    3. Type 定义新类型

使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名

object Test {
 def main(args: Array[String]): Unit = {
 
 type S=String
 var v:S="abc"
 def test():S="xyz"
 }
}

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值