Scala学习笔记之面向对象

时间:2023-02-25 23:46:54
Scala学习笔记之面向对象

创建对象

val greetStrings = new Array[String](3)

如果类还实现了apply方法,那么可以简写

val greetStrings = Array[String](3)

object

Scala学习笔记之面向对象

1.object声明时和类声明时一样

2.一个object可以继承一个类的实现,并可以覆盖方法

3.java中的所有接口在scala中都可以用做特质

4.特质可以继承,如果要实现抽象方法要加上abstract override

5.对象中可以混入特质,如果一个类声明混入一个接口,那么在对象声明时可以动态混入特质

6.混入特质的类中必须实现所有的抽象方法,负责必须设为abstract

7.如果一个类混入了多个同中方法,那么在最后的特质的方法被调用。

 

单例对象

object和类的区别

1.object不用创建

2.object没有构造方法

伴生对象

Scala学习笔记之面向对象

1.类和他的伴生对象可以相互访问私有属性

互相引用

当伴生对象引用伴生类要先创建对象、而伴生类引用伴生对象中的方法必须加上对象名

scala继承结构

  1.scala把所有类统一到Any下 

  2.java中的基本类型在Anyval下

  3.其他类都在AnyRef下,

  4.任何引用都可以设为null。

1.scala中的包和文件路径无关

2.scala中包可以嵌套,而且包也有作用域,这意味着子包可以引用父包。

3.可以使用java中的包声明方法来简化scala中的包声明。

4.在包中可以有一个包的类,和包名相同。

5.包权限控制:private[package-name]//注意scala中的权限有方向性

6.引入import或者import _或者 import java.awt.{Color,Font}

7.可以在任何地方引入包

8.scala默认导入java.lang scala以及Predef

9.scala支持静态导入

前缀方法

前缀就是把操作符放在对象前面来调用,scala仅仅支持+,-,!, 和 ~。每一个前缀方法都会被翻译成unary_prefix

对象相等

scala的==和!=用于比较两个对象的内容,而eq和ne用来表示比较两个对象的引用相等性。而这和Java恰恰相反

导入

Scala学习笔记之面向对象

导入

// easy access to Fruit

import bobsdelights.Fruit

// easy access to all members of bobsdelights

import bobsdelights._

// easy access to all members of Fruits

import bobsdelights.Fruits._

import Fruits.{Apple => McIntosh, Orange}

把Apple和Orange导入并且把Apple重命名为McIntosh

Scala学习笔记之面向对象

构造器

1.scala有一个主构造器和多个辐构造器

     class Person(private var i:Int,val s:String){

          print("Person contronstant");

          def this(value:Int){this();i = value}

     可以看到,在主构造器中可以声明类字段,且可以提供默认的参数,在类体中的语句都在构造时执行,且可以在主构造器前面加private来表示主构造器是私有的。

2.scala中的主构造器中的参数仅仅用于传递参数,在类中一定要声明类中使用的变量

3.辅助构造器的第一个语句必须是其他构造器

4.在scala中可以使用require来是数据符合一定的条件

5.在scala中,只有主构造器可以调用父类的构造器,java中任意的构造方法都可

6.为了克服2中的缺陷可以使用如下的声明

class Queue[T](private val leading: List[T],private val trailing: List[T]){

private def mirror =

if (leading.isEmpty) new Queue(trailing.reverse, Nil)

else this

def head = mirror.leading.head

def tail = {

val q = mirror

new Queue(q.leading.tail, q.trailing)

}

def enqueue(x: T) =

new Queue(leading, x :: trailing)

}

7.把主构造其设为私有的方法

class Queue[T] private (

private val leading: List[T],

private val trailing: List[T]

)

8.

this

java和scala中的构造顺序问题

Scala学习笔记之面向对象

问题:java在子类构造过程中调用父类的构造器可能会子类覆盖的方法,但是这时子类仅仅产生并未初始化,也就是说父类得到的结果是没有定义的,因此构造结果也无法定义。在C++中父类构造过程中调用的是父类的方法。

 解决方法:父类的使用未定义字段的字段设为lazy

懒值

懒值,在val声明时加上lazy,懒值是在使用的时候才产生的。

预初始化

预初始化中,子类预初始化字段在父类初始化之前就已经初始化

对于匿名类

new {

    val numerArg = 1 * x

    val denomArg = 2 * x

} with RationalTrait

对于继承

object twoThirds extends {

    val numerArg = 2

    val denomArg = 3

} with RationalTrait{...}

scala和Java的不同

1.scala不允许属性和方法 

抽象类

1.使用abstract关键字

2.抽象方法没有abstract,例子:def incl(x: Int): IntSet,子类实现时要用override关键字

3.抽象字段,没有初始值。

抽象类型

Scala学习笔记之面向对象

类型的收放问题

class Food

abstract class Animal {

    def eat(food: Food)

}

class Grass extends Food

class Cow extends Animal {

    override def eat(food: Grass) {} // This won’t compile,

}                                                       // but if it did,...

class Fish extends Food

val bessy: Animal = new Cow

bessy eat (new Fish) // ...you could feed fish to cows.

在java中无法禁止上面的问题,在继承结构中的子类无法精确控制它的方法参数

引用相关类型

定义:scala类中可以有type用来声明一个占位符,这样类型可以由各个子类控制,这样的好处就是有了精确的类型就可以调用特殊的方法。这个和继承具体的模板的方法得到效果类似

scala提供更加先进的类型控制,使用scala可以有效的控制子类的参数类型

class Food

abstract class Animal {

    type SuitableFood <: Food //<:用来表示SuitableFood的上界是Food

    def eat(food: SuitableFood)

}  

class Grass extends Food

class Cow extends Animal {

    type SuitableFood = Grass

    override def eat(food: Grass) {}

}

 

无参方法和空参方法

Scala学习笔记之面向对象

声明

无参方法

val height = contents.length

空参方法

val height() = contents.length

 

使用

空参方法在调用时可以加圆括号或者不加,但是无参方法一定不能加

访问一致性

无参方法可以实现访问一致性

区别

无参方法用在没有副作用的地方,而空参方法则用在有副作用的地方

继承

Scala学习笔记之面向对象

1.scala覆盖非抽象方法和抽象字段时使用override

2.调用父类用super

3.scala也支持protected

4.scala中只有主构造器可以调用父类的构造器,注意可以是父类任意的构造器。

as:class Employ(var name:String,var age:Int,val salary:Int) extends Person(name,age)

5.匿名子类,new Person("Fred"){def greeting="Greeting Fred"}

6.var只能覆盖抽象字段,而val可以在任何类中覆盖,覆盖普通类字段时要加上override

7.加上final就无法覆盖

实现

1.val只能用val实现

2.无参方法可以用无参方法或者val实现

覆盖

特质

Scala学习笔记之面向对象

混入

Scala学习笔记之面向对象

1.混入会把所有在特质中定义的公有属性和方法都集成到混入类,但是特质中的抽象字段必须在子类中重定义

2.

类混入

如果一个类没有继承父类,那么应该使用extends混入特质,当有一个继承时用with

class SavingAcount with Logged{}

trait FileLogged extends Logged{}

     

对象混入

var s = new SaveAccount with FileLogged

对象混入不能把特质混入final类

妙用

1.scala中的特质可以用来向一个类动态加入方法

     as:trait RectangeLike{def grow(),def tanslate()}

     val egg = new Double() with RectangeLike

  这儿Double中原来并没有grow和translate方法,但是egg对象却可以使用这两个方法

2.打破Java中的单继承

     由于trait可以继承自一个类,那么一个类就可使用通过混入一个特质来进行多继承。但是这是有限制的,如下

     as:trait LoggedException extends Exception{}

     classs UnhappyFrame extends JFrame with LoggedException{}//error

     这儿UnhappyFrame继承的类必须是混入的接口所继承的类的子类。

3.装饰器

装饰器

trait Doubling extends IntQueue {

    abstract override def put(x: Int) { super.put(2 * x) }

}

1.这人的特质继承了一个类,因此它仅能混入它继承类的子类中

2.特质使用abstract override来表明它要作为修饰器

3.traits further to the right take effect first. When you call a method on a class with mixins, the method in the trait furthest to the right is called first. If that method calls super, it invokes the method in the next trait to its left, and so on.

arlert

Scala学习笔记之面向对象

ensuring

def put(x: Int) { super.put(2 * x) ensuring(x>0) }

ensuring用于在结尾检测结果是否符合要求

getter和setter

scala中的setter和getter数升级模型,首先一个属性在开始的时候可以是public的,一旦需要对变量的存取进行控制,就可以把变量从命名,并以原来的名字定义getter和setter。

 

结构类型

结构类型指的是一个类型是由他的结构所决定的,就好像在动态语言中的鸭子类型。在任何需要类型的地方都可以使用结构类型。

var animals: List[Animal { type SuitableFood = Grass }] = Nil

def using[T <: { def close(): Unit }, S](obj: T)(operation: T => S) = {

    val result = operation(obj)

    obj.close()

    result

}

提取器

Scala学习笔记之面向对象

在样例类中,样例类仅能用在构造器匹配中,无法自定义,提取器中可以自定义。

unapply

object EMail{

   def apply(user: String, domain: String) = user +"@"+ domain

   def unapply(str: String): Option[(String, String)] = {

       val parts = str split "@"

       if (parts.length == 2) Some(parts(0), parts(1)) else None

   }

}

定义:unapply方法时,需要一个参数来提取值,返回值是一个Option类型的元祖,这个元祖可以由Some产生,如果未匹配就会返回None值

使用:"ssj@163.com" match { 

              case EMail(user, domain) => println(user+"AT"+domain)

              case _=>"can not extracting"}

在匹配时把选择子(这儿是"ssj@163.com" 传递给unapply方法),结果传递给EMail中的值,即user和domain。

 

unapplySeq

unapplySeq放回的是变长的列表

定义:def unapplySeq(first:T):Option[Seq[T]]

def unapplySeq(whole: String): Option[Seq[String]] =Some(whole.split("\\.").reverse)

 

注意

1.scala中有抽象字段,因此不能像java那样在类中定义属性时不加任何初始值,而要把属相设为初始值,对于var的属性可以设为初始值_,而对于val的属性则必须设为有用的值

易错

Scala学习笔记之面向对象

赋值的返回值

在其他的语言中赋值操作的结果是变量得到的值,可以用这个特性来简化代码,as (line = readLine()) != “”,但是在scala中赋值操作的结果是Unit,scala中不同类型的值比较永远是false。(事实上,在c/c++/java中不允许不同类型的值进行比较,而scala和python允许)