Scala的Class、Object、Trait

in #cn7 years ago (edited)

开发环境

ideaIU或ideaIC。

idea的scala插件,File-Setting-Plugins,搜索scala在线安装,或下载后离线安装Install plugin from disk。

加载scala的包,Project Structure,Global Libraries,添加scala-sdk。

基础

scala中,break和continue的实现

package com.padluo.spark.scala.basic

import scala.util.control.Breaks._

object BreakTest {
  def main(args: Array[String]): Unit = {
    // break
    breakable {
      for (i <- 1 to 10) {
        if (i == 2) {
          break()
        }
        println(i)
      }
    }

    // continue
    for (i <- 1 to 10) {
      breakable {
        if (i == 2) {
          break()
        }
        println(i)
      }
    }

  }
}

0 until 100 to 10的区别,until是0到9,相当于<,to是0到10,相当于<=。

scala用Java里面的类库

package com.padluo.spark.scala.basic

import java.text.SimpleDateFormat
import java.util.{Calendar, Date}

object UseJava {
  def main(args: Array[String]): Unit = {
    val sdf:SimpleDateFormat = new SimpleDateFormat("yy-MM-dd")
    val c = Calendar.getInstance()
    println(c.getTime)
    println(sdf.format(c.getTime))

    // Convert Code from Java,可以直接把Java代码贴到scala文件中来
    val sdf2: SimpleDateFormat = new SimpleDateFormat("yy-MM-dd")
    sdf2.format(new Date)
  }
}

Class、Object、Trait

类class里无static类型,类里的属性和方法,必须通过new出来的对象来调用,所以有main主函数也没用。

而object的特点是:

  • 可以拥有属性和方法,且默认都是"static"类型,可以直接用object名直接调用属性和方法,不需要通过new出来的对象(也不支持)。
  • object里的main函数式应用程序的入口。
  • object和class有很多和class相同的地方,可以extends父类或Trait,但object不可以extends object,即object无法作为父类。

构造函数

  • 一个主构造器(函数),其他是辅助构造器
  • 辅助构造器的实现体里,必须引用(调用)主构造器
  • 主构造器的参数,也会成为类的属性(?正确吗?)
  • 辅助构造函数的名称都是this
  • 辅助构造函数中必须以一个其他辅助构造器或主构造器的调用开始

Bean属性,定义getter和settet方法。

// TestVo.scala
package com.padluo.spark.scala.basic

import scala.beans.BeanProperty

class TestVo {
  // class 里的属性默认是private类型,object里的属性默认是static
  @BeanProperty var id = 10
  @BeanProperty var name = null
  @BeanProperty var addr = null
}

// TestVoMain.scala
package com.padluo.spark.scala.basic

object TestVoMain {
  def main(args: Array[String]): Unit = {
    var vo = new TestVo
    println(vo.getId)
  }
}

伴生对象

如何实现同个类既有普通方法又有静态方法?

伴生类和伴生对象可以相互访问彼此的私有成员。

package com.padluo.spark.scala.basic

class BanSheng {
  def add2(a: Int, b: Int): Int = {
    a + b
  }
}

object BanSheng {
  def add(a: Int, b: Int): Int = {
    a + b
  }

  def main(args: Array[String]): Unit = {
    BanSheng.add(1, 2) // 静态函数
    val banSheng = new BanSheng
    banSheng.add2(3, 4)
  }
}

javap BanSheng.class反编译后,

public class com.padluo.spark.scala.basic.BanSheng {
  public static void main(java.lang.String[]);
  public static int add(int, int);
  public int add2(int, int);
  public com.padluo.spark.scala.basic.BanSheng();
}

伴生对象的apply方法

package com.padluo.spark.scala.basic

class BanSheng(id: Int) {
  def add2(a: Int, b: Int): Int = {
    a + b
  }
}

object BanSheng {
  def apply(id: Int): BanSheng = {
    println("----apply-----")
    new BanSheng(id)
  }

  def add(a: Int, b: Int): Int = {
    a + b
  }

  def main(args: Array[String]): Unit = {
    BanSheng.add(1, 2) // 静态函数
    val banSheng = new BanSheng(1)
    banSheng.add2(3, 4)

    val c = BanSheng(200)
    val cc = BanSheng.apply(200)
  }
}

单例模式

package com.padluo.spark.scala.basic

class SingleTon {

}

object SingleTon {
  private var s:SingleTon = null

  def  getInstance():SingleTon = {
    if(s == null) {
      new SingleTon()
    } else {
      s
    }
  }

  def main(args: Array[String]): Unit = {
    val singleTon = SingleTon.getInstance()
    println(singleTon)
  }
}

继承

  • 继承关键词extends,多个用with。
  • 某类如果不想被继承,可定义为final类型
  • 用super调用父类的方法或属性
  • 重写方法时必须用override,可以重写字段,不想被重写则定义为final类型
  • 只有主构造器可以调父类的主构造器

Father.scala

package com.padluo.spark.scala.basic

class Father(name: String, age: Int) {
  def doEat(food: String) {
    println("eatting .." + food)
  }

  def printInfo2() {
    println("name:" + name + ",age:" + age)
  }
}

Son.scala

package com.padluo.spark.scala.basic

class Son(name: String, age: Int, addr: String) extends Father(name, age) {
  // 子类把name和age传入到父类中
  override def doEat(food: String) {
    println("my eatting .." + food)
  }

  def printInfo() {
    super.printInfo2()
    println("name:" + name + ",age:" + age + ",addr:" + addr)
  }
}

object Son {
  def main(args: Array[String]): Unit = {
    val s: Son = new Son("zhangsan", 30, "beijing")
    s.printInfo()
  }
}

Scala类层级结构

Scala里,每个类都继承自通用的名为Any的超类。因为所有的类都是Any的子类,所以定义在Any中的方法就是“共同的”方法:它们可以被任何对象调用。

Scala类层级结构

因为每个类都继承自Any,所以Scala程序里的每个对象都能用==、!=或equals比较,用hashCode做散列,以及用toString转为字符串。Any类里的等号和不等号方法被声明为final,因此他们不能再子类里重写。实际上,==总是与equals相同,!=总是与equeal相反。因此,独立的类可以通过重写equals方法改变==!=的意义。

Any有两个子类:AnyVal和AnyRef(相当于Java里的Object)。
AnyVal是Scala里每个内建值类的父类。有9个这样的值类:Byte、Short、Char、Int、Long、Float、Double、Boolean和Unit。其中的前8个都对应到Java的基本类型。这些值类都被定义为既是抽象的又是final的,不能使用new创造这些类的实例。Unit被用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。

AnyRef类是Scala里所有引用类(reference class)的基类。它其实是Java平台上java.lang.Object类的别名。因此Java里写的类和Scala里写的都继承自AnyRef。

Scala类与Java类的不同在于它们还继承自一个名为ScalaObject的特别trait。是想要通过ScalaObject包含的Scala编译器定义和实现的方法让Scala程序的执行更高效

scala.Null和scala.Nothing是用统一的方式处理Scala面向对象类型系统的某些“边界情况”的特殊类型。Null类是null引用对象的类型,它是每个引用类(继承自AnyRef的类)的子类。Null不兼容值类型。Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。然而,根本没有这个类型的任何值。Nothing的一个用处是它标明了不正常的终止。

Trait特质

为什么不可以继承多个父类?原因是多个父类里有相同函数或属性时,无法控制用哪个。

Scala的Trait相当于Java里的Interface,但Trait不仅可以定义函数,还可以有函数体实现。实现关键词是extends,实现多个Trait用with。当extends的多个Trait里有相同函数时,子类必须重写该函数。

  • 父trait里无函数体的函数,子类必须override
  • 重写父类里有函数体的函数,必须有关键词override
  • trait里的变量,都是val类型
  • 在trait里定义的的变量,必须是val类型,如果变量没初始化,子类必须override

案例1,

trait TestTrait {
  def fun()
}

反编译后为

public interface com.padluo.spark.scala.basic.TestTrait {
  public abstract void fun();
}

当def fun()改为def fun(){} 时,反编译结果如何?

trait TestTrait {
  def fun() {}
}

反编译后为(有问题???)

D:\Java\idea\IdeaProjects\spark-study\spark-core\target\classes\com\padluo\spark\scala\basic>javap TestTrait.class
Compiled from "TestTrait.scala"
public abstract class com.padluo.spark.scala.basic.TestTrait$class {
  public static void fun(com.padluo.spark.scala.basic.TestTrait);
  public static void $init$(com.padluo.spark.scala.basic.TestTrait);
}

D:\Java\idea\IdeaProjects\spark-study\spark-core\target\classes\com\padluo\spark\scala\basic>javap TestTrait$class.class
Compiled from "TestTrait.scala"
public abstract class com.padluo.spark.scala.basic.TestTrait$class {
  public static void fun(com.padluo.spark.scala.basic.TestTrait);
  public static void $init$(com.padluo.spark.scala.basic.TestTrait);
}

案例2,

trait TestTrait {
  def fun() {
    println("---")
  }

  def fun200()
}

反编译后为(有问题)

D:\Java\idea\IdeaProjects\spark-study\spark-core\target\classes\com\padluo\spark\scala\basic>javap TestTrait.class
Compiled from "TestTrait.scala"
public abstract class com.padluo.spark.scala.basic.TestTrait$class {
  public static void fun(com.padluo.spark.scala.basic.TestTrait);
  public static void $init$(com.padluo.spark.scala.basic.TestTrait);
}

D:\Java\idea\IdeaProjects\spark-study\spark-core\target\classes\com\padluo\spark\scala\basic>javap TestTrait$class.class
Compiled from "TestTrait.scala"
public abstract class com.padluo.spark.scala.basic.TestTrait$class {
  public static void fun(com.padluo.spark.scala.basic.TestTrait);
  public static void $init$(com.padluo.spark.scala.basic.TestTrait);

本文首发于steem,感谢阅读,转载请注明。

https://steemit.com/@padluo


微信公众号「padluo」,分享数据科学家的自我修养,既然遇见,不如一起成长。

数据分析


读者交流电报群

https://t.me/sspadluo


知识星球交流群

知识星球读者交流群