Scala语言学习三——类和对象

Scala 类和对象

类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。

scala 单例对象

在 Scala 中, 是没有 static 这个东西的, 但是它也为我们提供了单例模式的实现方法, 那
就是使用关键字 object, object 对象不能带参数。就是说每次调用这个单例对象的时候,不需要new,直接ScalaSingleton.saySomething(“滚犊子…”)就完事,参数也是。

/**
* 单例对象
*/
object ScalaSingleton {
def saySomething(msg: String) = {
println(msg)
}
}o
bject test {
def main(args: Array[String]): Unit = {
ScalaSingleton.saySomething("滚犊子....")
println(ScalaSingleton)
println(ScalaSingleton)
// 输出结果:
// 滚犊子....
// cn.demo.ScalaSingleton$@28f67ac7
// cn.demo.ScalaSingleton$@28f67ac7
}
}

类的定义和实例化

  • 在 Scala 中, 类并不用声明为 public,而是用class。

  • 我们可以使用class定义类,然后用 new 关键字来创建类的对象,

  • Scala 的类定义可以有参数,称为类参数。

  • 如果你没有定义构造器, 类会有一个默认的空参构造器
    关于类中变量的定义

  • var 修饰的变量, 这个变量对外提供 getter setter 方法

  • val 修饰的变量, 对外提供了 getter 方法,没有 setter

  • 如果主构造器中成员变量属性没有val var修饰的话,该属性不能被访问,相当于没有对外提供get

实例如下:

import java.io._
//没传入构造器,默认空参构造器
class Student {   
// _ 表示一个占位符, 编译器会根据你变量的具体类型赋予相应初始值
// 注意: 使用_ 占位符是, 变量类型必须指定


var name: String = _           //用var定义了一个参数,可以getter setter 
// val age: Int = _错误代码, val 修饰的变量不能使用占位符

val age: Int = 10        //用val定义了一个参数,可以getter,不可setter,所以不可变 
}


   def birthday(age1: Int) {  //编写一个方法birthday
      age=age+1
      println ("我已经" + age1+"岁了");
   }
}


object Test{
val name: String = "zhangsan"         //使用setter功能中,设立参数

def main(args: Array[String]): Unit = {

// 调用空参构造器,可以加() 也可以不加
val student = new Student()            //new 来实例化类

student.name = "laoYang"          //使用setter功能中,设立参数,可改变参数值

// 类中使用 val 修饰的变量不能更改
// student.age = 20

println(s"student.name ====== ${student.name} ${student.age}")       //用getter功能中,即调出该对象的函数

student.birthday(student.age)           //调用birthday该方法
}

以上实例的类定义了两个变量age和name,一个方法:birthday,方法没有返回值。
我们可以使用 new 来实例化类,并访问类中的方法和变量:

主构造器/辅助构造器

主构造器

定义在类后面的为类主构造器, 一个类可以有多个辅助构造器
定义个 2 个参数的主构造器

Student1(val name: String, var age: Int)

如果有了主构造器,之前的构造方法就可以不要了(下面的不要了)

//var name:String= _   //初始值是一个null
//var age:Int= _   
辅助构造器

辅助构造器, 使用 def this
在辅助构造器中必须先调用类的主构造器

def this(name: String, age:Int, gender: String){
this(name, age)   //在辅助构造器中必须先调用类的主构造器
this.gender = gender
}

实例

class Student1 (val name: String, var age: Int) {    //主构造器

var gender: String = _
def this(name: String, age:Int, gender: String){         //辅助构造器
this.gender = gender


object Test1{
def main(args: Array[String]): Unit = {
val s = new Student1("laoduan", 38)          //调用主构造器
println(s"${s.name} ${s.age}")
val s1 = new Student1("laoYang", 18, "male")         //调用辅助构造器
println(s"${s1.gender}")
}
}
}
}

访问权限问题

构造器的访问权限

在构造器前面加修饰权限
说明主构造器是私有的,外部类或外部对象不能访问

class Teacher   private (name:String,age:Int){`   

同样也适用于辅助构造器

private def this(name: String, age:Int, gender: String){

成员变量访问权限

成员变量前面如果加上了 private 修饰, 也就意味着, age 只能在这个类的内部以及其伴生类对象中可以访问修改, 其他外部类不能访问

class Student3 private (val name: String, private var age: Int) {

类的访问权限

类的前面加上private[this]标识这个类在当前包下都可见,当前包下的子包及其其他包不可见,伴生对象不能访问
类的前面加上private[包名]标识这个类在该包下及其子包可见

伴生对象/伴生类

在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。

Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。可以不用new。

当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。

伴生对象实例

/* 文件名:Marker.scala

  • author:菜鸟教程
  • url:www.runoob.com
    */
class Student3 private (val name: String, private var age: Int) {
var gender: String = _

def this(name: String, age:Int, gender: String){
this(name, age)
this.gender = gender
} 
def getAge = 18
}

 // 类的伴生对象
object Student3 {
def main(args: Array[String]): Unit = {
// 伴生对象可以访问类的私有方法和属性
val s3 = new Student3("Angelababy", 30)
s3.age = 29
println(s"${s3.age}")
// println(s"${s3.province}") 伴生类不能访问
}
}

apply 方法在伴生对象中的应用

class Student3 private (val name: String, private var age: Int) {
var gender: String = _

def this(name: String, age:Int, gender: String){
this(name, age)
this.gender = gender
} 
def getAge = 18
}

伴生对象

object Student3 {

def apply(name:String,age:Int):Student3 ={
//apply方法中,可以对类进行初始化的工作,到时别人调用时候就可以直接调用不用new
new Student3 (name,age)
}
def main(args: Array[String]): Unit = {
val Student =Student3 ("林"12) //不用new
}
}

特质

Scala Trait(特质) 相当于 Java 的接口, 实际上它比接口还功能强大。
与接口不同的是, 它还可以定义属性和方法的实现。
一般情况下 Scala 的类只能够继承单一父类, 但是如果是 Trait(特质) 的话就可以继承多个,实现了多重继承。 使用的关键字是 trait .

trait T2 {
// 定义一个属性
val className: String = "NB 大神班"
// 定义一个没有实现的方法
def teacherSay(name: String)
// 定义个带有具体的实现的方法
def doSomething() = {
println("改吃中午饭了...")

以上Trait(特征)由两个方法组成:isEqual 和 isNotEqual。isEqual 方法没有定义方法的实现,isNotEqual定义了方法的实现。子类继承特征可以实现未被实现的方法。

  • 父类已经实现了的功能, 子类必须使用 override 关键字重写
  • 父类没有实现的方法, 子类必须实现

抽象类

在 Scala 中, 使用 abstract 修饰的类称为抽象类. 在抽象类中可以定义属性、 未实现的方法和
具体实现的方法。

  • 使用关键字abstract 定义一个抽象类
  • 可以没有具体实现的方法
  • 也可以有具体实现的方法
/*
* abstract 修饰的类是一个抽象类
* */
abstract class Animal {
println("Animal's constructor ....")
// 定义一个 name 属性
val name: String = "animal"
// 没有任何实现的方法
def sleep()
// 带有具体的实现的方法
def eat(f: String): Unit = {
println(s"$f")
}
}

混入特质

混入特质的两种方式

方式一,在创建该类的实例的时候混入特质

  val student = new Student with Fly with ScalaTrait
    //student.hello("老羊")
    student.fly("gaoxing")
    student.small("丁丁")

方式二,在定义该类的时候混入特质

object ScalaTraitImpl extends ScalaTrait with Fly{
 

 // 如果特质中某个方法有具体的实现,在子类继承重写的时候,必须使用override关键字
    
    override def small(name: String): Unit = {
        println(s"丁丁 对 $name 哈哈大笑")
    }}

继承

承是面向对象的概念, 用于代码的可重用性。 被扩展的类称为超类或父类, 扩展的类称为派生类或子类。 Scala 可以通过使用 extends 关键字来实现继承其他类或者特质。

  • with 后面只能是特质

  • 父类已经实现了的功能, 子类必须使用 override 关键字重写

  • 父类没有实现的方法, 子类必须实现

class Dog extends Animal {
println("Dog's constructor ...")
override val name: String = "Dog"
def sleep(): Unit = {
println("躺着睡...")
}
override def eat(f: String): Unit = {
println("")
}
}

scala中可以实现一个类同时继承多个特质

  • 在scala中第一个继承抽象类或者特质,只能使用关键字extends
  • 如果想继承多个特质的话,可以在extends之后使用with关键字
package cookBook.chapter8

//轮胎
trait tire{
  def run: Unit ={
    println("I can run fast")
  }
}

//方向盘
trait SteeringWheel{
  def control: Unit ={
    println("I can control the cars'direction")
  }
}

//同时继承多个特质
class Roadster extends  tire with SteeringWheel{
  def display(): Unit ={
    println("I'm a Roadster")
  }
}

//敞篷跑车
object Roadster extends App{
  var roadster = new Roadster
  roadster.display()
  roadster.run
  roadster.control
}

final 关键字

  • 被 final 修饰的类不能被继承;
  • 被 final 修饰的属性不能重写;
  • 被 final 修饰的方法不能被重写。

type 关键字

Scala 里的类型, 除了在定义 class,trait,object 时会产生类型, 还可以通过 type 关键字来声明
类型。
type 相当于声明一个类型别名,就是用S代替String::

// 把 String 类型用 S 代替
type S = String
val name: S = "小星星"
println(name)

通常 type 用于声明某种复杂类型, 或用于定义一个抽象类型在这里插入图片描述

模式匹配

  • Scala 提供了强大的模式匹配机制,应用也非常广泛。

  • 一个模式匹配包含了一系列备选项,每个都开始于关键字 case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。

  • match 对应 Java 里的 switch,但是写在选择器表达式之后。即: 选择器 match {备选项}。

  • match 表达式通过以代码编写的先后次序尝试每个模式来完成计算,只要发现有一个匹配的case,剩下的case不会继续匹配。

object ScalaMatchCase {

    def main(args: Array[String]): Unit = {

// 匹配字符串内容--------------------------------------
        def contentMatch(str: String) = str match {
            case "hello" => println("hello")
            case "Dog" => println("Dog")
            case "1" => println("1")
            case "1" => println("2")
            case _ => println("匹配不上") //_表示默认的全匹配备选项,即没有找到其他匹配时的匹配项,类似 switch 中的 default。
        }

        println("----------匹配字符串内容--------")
        contentMatch("hello")
        contentMatch("Dog")
        contentMatch("1")
        contentMatch("fuck")





      // 匹配数据类型--------------------------------------


   println("----------匹配数据类型--------")
        def typeMatch(tp: Any) = tp match {
            case x: Int => println(s"Int $x")
            case y: Long => println(s"Long $y")
            case b: Boolean => println(s"boolean $b")
            case _ => println("匹配不上")
        }
        typeMatch(1) 
        typeMatch(10L)
        typeMatch(true)
        typeMatch("Scala")



  // 匹配Array-----------------------------------
        println("----------匹配Array--------")
        def arrayMatch(arr: Any) = arr match {
            case Array(0) => println("只有一个0元素的数组")
            case Array(0, _) => println("以0开头的,拥有2个元素的数组")
            case Array(1, _, 3) => println("已1开头,3结尾,中间为任意元素的三个元素的数组")
            case Array(8, _*) => println("已8开头,N个元素的数组") // _*标识0个或者多个任意类型的数据
        }
        arrayMatch(Array(0))
        arrayMatch(Array(0, "1"))
        arrayMatch(Array(1, true, 3))
        arrayMatch(Array(8,9,10,100,666))







  // 匹配List-------------------------------
       
        def listMatch(list: Any) = list match {
            case 0 :: Nil => println("只有一个0元素的List")
            case 7 :: 9 :: Nil => println("只有7和9元素的List")
            case x :: y :: z :: Nil => println("只有三个元素的List")
            case m :: n if n.length > 0 => println("------") // 拥有head,和 tail的数组   if n.length > 0  守卫
            case _ => println("匹配不上")
        }
        listMatch(List(0))
        listMatch(List(7,9))
        listMatch(List(8,9, 666))
        listMatch(List(666))











//匹配元组----------------------------------
val tup = (1, 3, 7)
def tupleMatch(tuple:Any)=tuple match {

case (0,_) => println(“元组第一个元素为0,第二个是任意数据,且只有两个”)

case (x,m,k) => println("拥有是哪个元素的元组")

case(_,"AK47")=>println("第一个任意,,第二个ak47,两个元素")

//错误案例   case (666, _*, 5) => println(w)   //有数量限制
case _ => println("else")
}


//匹配对象---------------------------------

//样例类, 模式匹配, 封装数据(多例) ,不用 new 即可创建实例

case class SubmitTask(id: String, name: String)

case class HeartBeat(time: Long)

//样例对象, 模式匹配(单例)

case object CheckTimeOutTask

def objmatch(obj:Any) =obj match{

case SubmitTask(id, name) => {
println(s"$id, $name")
}
case HeartBeat(time) => {
println(time)
}

case "字符串" => {
println("字符串")
}

样例类/样例对象/模式匹配

  • 样例类,使用 case 关键字 修饰的类, 其重要的特征就是支持模式匹配

  • 样例类默认是实现了序列化接口

//样例类, 模式匹配, 封装数据(多例) ,不用 new 即可创建实例
case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
//样例对象, 模式匹配(单例)
case object CheckTimeOutTask
val arr = Array(CheckTimeOutTask, new HeartBeat(123),
HeartBeat(88888), new HeartBeat(666), SubmitTask("0001",
"task-0001"))
val i = Random.nextInt(arr.length)
val element = arr(i)
println(element)
element match {
case SubmitTask(id, name) => {
println(s"$id, $name")
}c
ase HeartBeat(time) => {
println(time)
}c
ase CheckTimeOutTask => {
println("check")
}
}
发布了44 篇原创文章 · 获赞 0 · 访问量 861

猜你喜欢

转载自blog.csdn.net/heartless_killer/article/details/103338226