首页 > 技术文章 > Scala

qidi 2019-10-30 15:19 原文

1.类和对象

//1. Scala中类和对象的创建
object Demo01 {//单例对象,里边是用来定义静态内容的
//定义一个类
//1. 如果构造器是空的可以省略(),2. 如果类时空的可以省略{}
class Person
  //程序的入口,相当于java中的main方法
  def main(args: Array[String]): Unit = {
    //创建对象
    val p=new Person()
    println(p)
  }
}
View Code

2. 成员变量的定义和初始化

/**
  * 1. 定义一个Person类,包含一个姓名和年龄字段
  * 2. 创建一个名为"张三"、年龄为20岁的对象
  * 3. 打印对象的名字和年龄
  */
object Demo03 {

  //定义Person类
  class Person {
    //定义成员变量
    //var类型可以使用 _来初始化成员变量,val类型只能手动初始化
    /**
      * - String => null
      * - Int => 0
      * - Boolean => false
      * - Double => 0.0
      * - ...
      */
    var name: String = ""
    var age: Int = _
  }

  def main(args: Array[String]): Unit = {
    //创建对象
    val p = new Person
    //给成员变量赋值
    p.name = "刘亦菲"
    p.age = 38
    println(s"姓名是${p.name},年龄是${p.age}")

  }
}
View Code

3. 定义成员方法

package com.itheima.scala.oop

object Demo05 {
  //1.定义customer类
  class Customer{
    //2.定义Customer中成员变量和方法
    //val name:String=""
    //val name=""
    var name:String=_
    var sex:String=_
    //成员方法
    //简化版
    def  printHello(msg:String)= println(msg);


  }

  def main(args: Array[String]): Unit = {
    val c=new Customer
    c.name="刘亦菲"
    c.sex="female"
    println(c.name+"   "+c.sex)
    c.printHello("Hello World")
  }
}
View Code

4. 访问修饰符

//演示访问修饰符,scala中没有public
object Demo06 {

  class Person {
    private var name: String = _
    private var age = 0

    def getName = this.name

    def setName(name: String) = this.name = name

    def getAge = this.age

    def setAge(age: Int) = this.age = age

    //private def getNameAndAge()=(this.name,this.age)
    private def getNameAndAge() = this.name -> this.age
  }

  def main(args: Array[String]): Unit = {
    val p = new Person
    //下面三行报错
    //p.name="刘德华"
    //p.age="18"
    //p.getNameAndAge()
    p.setName("迪丽热巴")
    p.setAge(19)

    println(p.getName + "  " + p.getAge)

  }
}
View Code

5. 类的构造器

A::主构造器

  • 主构造器的参数列表是直接定义在类名后面,添加了val/var表示直接通过主构造器定义成员变量

  • 构造器参数列表可以指定默认值

  • 创建实例,调用构造器可以指定字段进行初始化

  • 整个class中除了字段定义和方法定义的代码都是构造代码

//演示主构造器
object Demo07 {
  class Person(var name:String="",var age:Int=0){
    //输出调用主构造器
    //类中除了字段定义和成员方法都是构造代码,主构造器执行一次,构造代码执行一次
    println("主构造器调用啦")
  }
  def main(args: Array[String]): Unit = {
    val p1=new Person("zhangsan",29)
    println(p1.name+"  "+p1.age)
    println("-"*20)

    //创建空对象
    val p2=new Person
    println(p2.name+"  "+p2.age)
    println("-"*20)

    //只对age赋值
    val p3=new Person(age =40)
    println(p3.name+"  "+p3.age)
    println("-"*20)
  }

}
View Code

B:辅助构造器

  • 定义辅助构造器与定义方法一样,也使用def关键字来定义

  • 这个方法的名字为this

  • 辅助构造器的第一行代码,必须要调用主构造器或者其他辅助构造器
object Demo08 {
  class  Customer(var name:String="",var address:String=""){
    def this(data:Array[String]){
      this(data(0),data(1));//这个this()表示调用的是本类的主构造器
    }
  }

  def main(args: Array[String]): Unit = {
    //创建对象
    //主构造器
    val  c1=new Customer
    val c2=new Customer(name="刘亦菲")
    val c3=new Customer(address="北京")
    val c4=new Customer("刘德华","香港")

    //思路二
    val c5=new Customer(Array("迪丽热巴","新疆"))
    println(c5.name+"  "+c5.address)
  }

}
View Code

6. 单例对象

  scala中没有想java中的静态成员,要想定义类似于java中static变量,方法,就要使用到scala中的单例对象--object

A:定义单例对象和其中的方法

  • 定义单例对象和定义类很像,就是把class换成object

  • 在object中定义的成员变量类似于Java的静态变量

  • 可以使用object直接引用成员变量

//演示Scala中的单列对象,类似于java中的静态成员
object Demo09 {//定义了单例对象 对象名:Demo09
  object Dog{
    var LEG_NUM:Int=4
  }

  //单列对象中定义成员方法
  object PrintUtil{
    //定义一个方法,用来打印15个减号

    def show()=println("-"*15)
  }

  def main(args: Array[String]): Unit = {
    println(Dog.LEG_NUM)
    PrintUtil.show()
  }
}
View Code

B:工具类案例

/**
  * 编写一个DateUtil工具类专门用来格式化日期时间
  * 定义一个方法,用于将日期(Date)转换为年月日字符串,例如:2030-10-05
  */
import java.text.SimpleDateFormat
import java.util.Date

//scala中定义工具类
object Demo10 {

  object DataUtil {
    def format(date: Date) = {
      val sdf = new SimpleDateFormat("yyyy-MM-dd MM:mm:ss")
      sdf.format(date)
    }
  }

  def main(args: Array[String]): Unit = {
    print(DataUtil.format(new Date()))
  }

}
View Code

7. main方法

  scala和Java一样,如果要运行一个程序,必须有一个main方法。而在Java中main方法是静态的,而在scala中没有静态方法。在scala中,这个main方法必须放在一个单例对象中。还有一种方法是继承App特质。

//测试程序的执行,继承app trait(特质的啥意思,可以理解为java中的接口)
object Demo12 extends App {
  println("Hello Scala")
}
View Code

8. 伴生对象

  一个class和object具有同样的名字,这个object称为伴生对象,这个class称为伴生类。

A:定义伴生对象

  • 伴生对象必须要和伴生类一样的名字

  • 伴生对象和伴生类在同一个scala源文件中

  • 伴生对象和伴生类可以互相访问private属性

//演示伴生对象
object Demo13 {
  class CustomerService{//伴生类
    def save()=println(CustomerService.name+"保存客户")

  }
  object CustomerService{//伴生对象
    private var name="CustomerService"

  }

  def main(args: Array[String]): Unit = {
    val cs =new CustomerService
    cs.save()
  }

}
View Code

B:private[this]访问权限

  
/*
*会编译报错,移除[this]就可以访问了
*/
class Person(private[this] var name:String)
  
  object Person {
    def printPerson(person:Person): Unit = {
      println(person.name)
    }
  }
  
  def main(args: Array[String]): Unit = {
    val person = new Person("张三")
    Person.printPerson(person)
  }
View Code

C:apply方法

import com.itheima.scala.oop.Demo14.Person

//测试伴生对象的apply方法 让创建对象省去 new的动作
object Demo15 {
  class Person(var name:String="",var age:Int=0){

  }
  object Person{
    def apply(name:String,age:Int)=new Person(name,age)
  }

  def main(args: Array[String]): Unit = {
    val p=new Person("亚索",31)
    print(p.name+"  "+p.age)

    //可以理解为这是理解糖
    val p2=Person("劫",40)

    //这实际就是调用,上面是简写
    val p3=Person.apply("盖伦",37)
  }
}
View Code

9. 继承

A:类继承

object Demo16 {
  //定义父类
  class Person{
    var name:String=""
    def getName()=this.name
  }

  class Student extends Person
  //定义子类

  def main(args: Array[String]): Unit = {
      //创建类的对象
    val s=new Student
    s.name="李世民"
    print(s.getName())
  }
}
View Code

B:单例对象继承

object Demo17 {
  //定义父类
  class Person{
    var name:String=""
    def getName()=this.name
  }

  object Student extends Person

  def main(args: Array[String]): Unit = {
      //创建类的对象
    Student.name="和珅"
    print(Student.getName())
  }
}
View Code

C:override和super

  • 子类要覆盖父类中的一个方法,必须要使用override关键字

  • 使用override来重写一个val字段

  • 使用super关键字来访问父类的成员方法

10. 类型判断

A:isInstanceOf和asInstanceOf

  • isInstanceOf判断对象是否为指定类的对象

  • asInstanceOf将对象转换为指定类型

  • isInstanceOf 只能判断对象是否为指定类以及其子类的对象,而不能精确的判断出,对象就是指定类的对象
object Demo19 {

  class Person

  class Student extends Person

  def main(args: Array[String]): Unit = {
    val s = new Student

    if (s.isInstanceOf[Student]) {
      print("是Student类型")
    } else {
      print("不是Student类型对象,现在需要转换为Student")
      s.asInstanceOf[Student]
    }
  }
}
View Code

B:getClass和classOf

  • p.getClass可以精确获取对象的类型

  • classOf[x]可以精确获取类型

  • 使用==操作符可以直接比较类型

object Demo20 {

  class Person


  class Student extends Person


  def main(args: Array[String]): Unit = {
    val s: Person = new Student
    println(s.isInstanceOf[Person]) //只能做大致判断,传入Person类或者其子类都会返回true

    println(s.getClass == classOf[Person]) //可以做精细化判断,必须指定的类型才会返回true,因为s是new的Student类型对象,不是Person 返回false

    println(s.getClass == classOf[Student])
  }

}
View Code

11. 抽象类

如果类的某个成员在当前类中的定义是不包含完整的,它就是一个抽象类

不完整定义有两种情况:

  1. 方法没有方法体(抽象方法

  2. 变量没有初始化(抽象字段

A:抽象方法

object Demo21 {

  //定义抽象类表示所有的图形
  abstract class Shape {
    def area(): Double //抽象方法
  }

  class Square(var edge: Double) extends Shape {
    override def area(): Double = edge * edge
  }

  class Rectangle(var length: Double, var width: Double) extends Shape {
    override def area(): Double = length * width
  }

  class Circle(var radius: Double) extends Shape {
    override def area(): Double = 3.14 * radius * radius
  }


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

    val s = new Square(5)
    println(s.area())

    val r = new Rectangle(10, 5.2)
    println(r.area())

    var c = new Circle(3)
    println(c.area())

  }

}
View Code

B:抽象字段

// 定义一个人的抽象类
abstract class Person6 {
  // 没有初始化的val字段就是抽象字段
  val WHO_AM_I:String
}

class Student6 extends Person6 {
  override val WHO_AM_I: String = "学生"
}

class Policeman6 extends Person6 {
  override val WHO_AM_I: String = "警察"
}

object Main6 {
  def main(args: Array[String]): Unit = {
    val p1 = new Student6
    val p2 = new Policeman6

    println(p1.WHO_AM_I)
    println(p2.WHO_AM_I)
  }
}
View Code

12. 匿名内部类

object Demo22 {

  //定义一个抽象类,里面有一个sayHello的抽象方法

  abstract class Person {
    def sayHello(msg: String)
  }

  def main(args: Array[String]): Unit = {
    new Person() { //小括号可以省略不写
      override def sayHello(msg: String): Unit = println(msg)
    }.sayHello("我是通过匿名内部类调用的方法")
    println("-" * 40)

    val p = new Person {
      override def sayHello(msg: String): Unit = println(msg)
    }

    p.sayHello("第二种方法调用匿名内部类中的方法")
  }

}
View Code

13. 特质

  • 特质是scala中代码复用的基础单元
  • 它可以将方法和字段定义封装起来,然后添加到类中
  • 与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。
  • 特质的定义和抽象类的定义很像,但它是使用trait关键字
  • 使用extends来继承trait(scala不论是类还是特质,都是使用extends关键字)

  • 如果要继承多个trait,则使用with关键字

A:trait作为接口使用

//trait相当于java中的接口
object Demo23 {

  trait Logger {
    def log(msg: String)
  }

  class ConsoleLogger extends Logger {
    override def log(msg: String): Unit = print(msg)
  }

  def main(args: Array[String]): Unit = {
    var cl = new ConsoleLogger
    cl.log("调用你了")

  }

}
View Code
//继承多个特质trait
object Demo24 {

  trait MessageSender {
    def send(msg: String)
  }

  trait MessageReceiver {
    def receive(): String
  }

  class MessageWorker extends MessageSender with MessageReceiver {
    override def send(msg: String): Unit = println(msg)

    override def receive(): String = "你发的消息我收到了,但是我不同意"
  }

  def main(args: Array[String]): Unit = {
    val mw = new MessageWorker
    mw.send("我喜欢你很久了")
    print(mw.receive())
  }
}
View Code

B:定义具体的方法

//演示特质中是可以定义具体方法
object Demo25 {

  trait Logger {
    def log(msg: String) = print(msg)
  }

  class UserService extends Logger {
    def add() = log("添加用户")
  }

  def main(args: Array[String]): Unit = {
    val us = new UserService
    us.add()
  }

}
View Code

C. trait中定义具体的字段和抽象的字段

object Demo26 {

  trait Logger {
    val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E")

    val TYPE: String

    def log(msg: String)
  }

  class ConsoleLogger extends Logger {
    override val TYPE: String = "控制台信息"

    override def log(msg: String): Unit = print(s"${TYPE}${sdf.format(new Date())}  ${msg}")
  }
  
  def main(args: Array[String]): Unit = {
    val con = new ConsoleLogger
    con.log("我是一条日志信息")
  }

}
View Code

D. 使用trait实现模板模式

  在一个特质中,具体方法依赖于抽象方法,而抽象方法可以放到继承trait的子类中实现,这种设计方式也称为模板模式。

  • trait中定义了一个抽象方法

  • trait中定义了其他的几个具体方法,会调用抽象方法

  • 其他实现类可以来实现抽象方法

  • 真正调用trait中具体方法的时候,其实会调用实现类的抽象方法实现

package com.itheima.scala.oop

object Demo27 {

  trait Logger {
    def log(msg: String)

    def info(msg: String) = log("普通日志" + msg) //具体的输出格式已经定义好了,把要输出的内容交给子类来实现
    def warn(msg: String) = log("警告日志" + msg)

    def error(msg: String) = log("错误日志" + msg)
  }

  class ConsoleLogger extends Logger {
    override def log(msg: String): Unit = println(msg) //函数回调
  }

  def main(args: Array[String]): Unit = {
    val cl = new ConsoleLogger
    cl.info("我是普通日志")
    cl.warn("我是警告日志")
    cl.error("我是错误日志")

  }

  class FileLogger extends Logger {
    override def log(msg: String): Unit = println("我是写入到文件中的")
  }

}
View Code

E:对象混入trait

object Demo28 {

  trait Logger {
    def log(msg: String) = print(msg)
  }

  class UserService

  def main(args: Array[String]): Unit = {
    val us = new UserService with Logger
    us.log("对象混入调用方法")
  }

}
View Code

F:trait实现调用链模式

 

G:trait的构造机制

  • trait也有构造代码,但和类不一样,特质不能有构造器参数

  • 每个特质只有一个无参数的构造器。

  • 一个类继承另一个类、以及多个trait,当创建该类的实例时,它的构造顺序如下:

    1. 执行父类的构造器

    2. 从左到右依次执行trait的构造器

    3. 如果trait有父trait,先构造父trait,如果多个trait有同样的父trait,则只初始化一次

    4. 执行子类构造器

object Demo30 {

  trait Logger {
    println("执行构造器")

  }

  trait MyLogger extends Logger {
    println("执行MyLogger构造器")
  }

  trait TimeLogger extends Logger {
    println("执行TimeLogger构造器")
  }

  class Person {
    println("执行person构造器")
  }

  class Student extends Person with MyLogger with TimeLogger {
    println("执行Student构造器")
  }

  def main(args: Array[String]): Unit = {
    val s = new Student //1. 限制性父类构造器,2. 在从左往右执行特质构造器 3. 特质如果有父类则限制性父类
  }

}
View Code

H:trait继承class

//trait继承class
object Demo31 {

  class MyUtils {
    def printMsg(msg: String) = println(msg)
  }

  trait Logger extends MyUtils {
    def log(msg: String) = printMsg(msg)
  }

  class Person extends Logger {
    def sayHello(msg: String) = log(msg)
  }

  def main(args: Array[String]): Unit = {
    val p = new Person
    p.sayHello("今天最好一行代码")
  }

}
View Code

 

推荐阅读