scala要点总结4:面向对象

一:类和构造函数

1. 类和构造函数

object A {
  def main(args: Array[String]): Unit = {
    val xiaoMing = new Boy("xiaoming", 20)
    val xiaoGang = new Boy("xiaoGang", 18, "china")

    println(xiaoMing)
    println(xiaoGang)
  }
}

class Boy(name : String, age : Int) {
  // 上面紧跟在类名后面的为主构造器

  // 属性,不需要get,set方法
  // var 修饰默认可以获取和修改,val 修饰只能获取,无法修改
  // 下划线表示给个默认值,String默认值是null
  var country : String = _

  // 辅助构造器用于实现构造器的重载扩展
  def this(name : String, age : Int, country : String){
    // 第一行必须先调用主构造器
    this(name, age)
    this.country = country
  }

  override def toString: String = name + age + country
}

2. 主构造函数的参数修饰符

定义5个类,以及对应的字节码反编译成Java后文件:

/** class A(name : String) */
public class A
{
  public A(String name) {}
}

/** class B(val name : String) */
public class B
{
  private final String name;
  
  public String name()
  {
    return this.name;
  }
  
  public B(String name) {}
}

/** class C(var name : String) */
public class C
{
  private String name;
  
  public C(String name) {}
  
  public void name_$eq(String x$1)
  {
    this.name = x$1;
  }
  
  public String name()
  {
    return this.name;
  }
}

/** class D(private val name : String) */
public class D
{
  private final String name;
  
  private String name()
  {
    return this.name;
  }
  
  public D(String name) {}
}

/** class E(private[this] val name : String) */
public class E
{
  public E(String name) {}
}

所以,小结如下:

主构造器参数 生成的字段 生成的方法
name:String 不生成任何字段 不生成任何方法
val/var name:String 私有字段 公共的getter/setter、getter方法
private val/var name:String 私有字段 私有的getter/setter、getter方法
private[this] val/var name:String 不生成任何字段 不生成任何方法

二:单例对象和伴生对象

单例(Singleton)对象是一个通过使用object关键字而不是使用class关键字声明的对象,Scala没有java那样的static的概念,因此需要通过单例对象提供程序执行的入口点,或者用于工具类,常量类的存放。上节的object A 就是单例对象。

当单例对象和同一文件中的类名一致时,此单例对象就称同名类的伴生对象。类和其伴生对象可以互相访问各自的私有方法。

class Singleton{
  private var calssValue : String = "class"

  // 访问伴生对象的私有属性
  def m = println(Singleton.objectValue)
}

object Singleton {
  private var objectValue : String = "object"

  def main(args: Array[String]): Unit = {
    var s = new Singleton()
    // 访问类的私有属性
    println(s.calssValue)
    s.m
  }
}

三:特质、抽象类和继承

trait(特质)和Java的接口类似。在Scala中,继承父类只能单继承,但是实现trait可以多个。trait可以定义属性和方法的实现,Java1.8开始也可以,之前版本不行。

当实现单个trait时,直接使用extends即可,但是实现多个trait时,第二个开始使用with关键字。

class Human extends Run with Talk {
  override def run: Unit = println("can run")
  override def talk: Unit = println("can talk")
}

trait Run {
  def run
}

trait Talk {
  def talk
}

四:apply 和 unapply方法

当一个类的实例后直接跟参数列表时,编译器会调用该实例上的apply方法,一般都是在类的伴生对象中定义apply方法,用于简化类的创建。

同时,unapply方法的目的是提取正在寻找的特定值,当使用match语句比较提取器对象时,将自动执行unapply方法。

object a {
  def main(args: Array[String]): Unit = {
    val h1 = new Human("xiaoming", 1)
    val h2 = new Human("xiaoming", 1)
    println(h1 == h2) // false

    val h3 = Human
    val h4 = Human
    println(h3 == h4) // true

    val h5 = Human("xiaoming", 1)
    val h6 = Human("xiaoming", 1)
    println(h5 == h6) // false

    val humanList = List(h1, h2, h3, h4, h5, h6, a)
    for (h <- humanList) {
      h match {
        case Human("xiaoming", _) => println("it is xiaoming")
        case Human => println("it's human, but I do not know")
        case _ => println("not human")
      }
    }
    /*
     * it is xiaoming
       it is xiaoming
       it's human, but I do not know
       it's human, but I do not know
       it is xiaoming
       it is xiaoming
       not human
     */
  }
}

class Human(){
  var name : String = _
  var age : Int = _

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

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

  def unapply(human: Human): Option[(String, Int)] = {
    if (human == null)
      None
    else
      Some(human.name, human.age)
  }
}

猜你喜欢

转载自blog.csdn.net/zhanht/article/details/89043773
今日推荐