zoukankan      html  css  js  c++  java
  • Scala_对象

    对象

    单例对象

    • Scala并没有提供Java那样的静态方法或静态字段,但是,可以采用 object关键字实现单例对象,具备和Java静态方法同样的功能。

    • 可以看出,单例对象的定义和类的定义很相似,明显的区分是,用object 关键字,而不是用class关键字

    object Person{
     private var lastId = 0
     def newPersonId()={
       lastId += 1
       lastId
    }
    }
    printf("The first person id is %d.
    " , Person.newPersonId())
    printf("The Second person id is %d. " , Person.newPersonId())
    printf("The Third person id is %d. " , Person.newPersonId())
    The first person id is 1.
    The Second person id is 2.
    The Third person id is 3.

    伴生对象

    • 在Java中,我们经常需要用到同时包含实例方法和静态方法的类,在Scala中可以通过伴生对象来实现

    • 当单例对象与某个类具有相同的名称时,它被称为这个 类的“伴生对象”。

    • 类和它的伴生对象必须存在于同一个文件中,而且可以 相互访问私有成员(字段和方法)

    class Person {
     private var id = Person.newPersonId() //调用了伴生对象中的方法
     private var name = ""
     def this(name:String){
       this()
       this.name = name
    }
     def info(): Unit ={
       printf("The id of %s is %d. " , name , id)
    }
    }
    object Person{
     private var lastId = 0
     private def newPersonId()={
       lastId += 1
       lastId
    }
     def main(args: Array[String]): Unit = {
       val person1 = new Person("Ziyu")
       val person2 = new Person("Minxing")
       person1.info()
       person2.info()
    }
    }
    • 从上面结果可以看出,伴生对象中定义的newPersonId() 实际上就实现了Java中静态(static)方法的功能

    • Scala源代码编译后都会变成JVM字节码,实际上, 在编译上面的源代码文件以后,在Scala里面的class 和object在Java层面都会被合二为一,class里面的成 员成了实例成员,object成员成了static成员

    • 为了验证这一点,我们可以一起测试一下。

    • 这里做一点小小修改, 那就是把object Person中的 newPersonId()方法前 面的private去掉

    class Person {
     private var id = Person.newPersonId() //???????????
     private var name = ""
     def this(name:String){
       this()
       this.name = name
    }
     def info(): Unit ={
       printf("The id of %s is %d. " , name , id)
    }
    }
    object Person{
     private var lastId = 0
     def newPersonId()={
       lastId += 1
       lastId
    }
     def main(args: Array[String]): Unit = {
       val person1 = new Person("Ziyu")
       val person2 = new Person("Minxing")
       person1.info()
       person2.info()
    }
    }
    • 在Shell命令提示符状态下,输入以下命令编译并执行:

    [root@slave2 ~]# scalac test.scala
    [root@slave2 ~]# ll
    total 32736
    -rw-------. 1 root root     1260 Jul  2 19:02 anaconda-ks.cfg
    -rw-r--r--. 1 root root 33485703 May 15 00:56 elasticsearch-5.5.2.tar.gz
    -rw-r--r--. 1 root root     2106 Aug 18 10:25 Person.class
    -rw-r--r--. 1 root root      958 Aug 18 10:25 Person$.class
    -rw-r--r--. 1 root root      171 Aug 18 05:56 test1.scala
    -rw-r--r--. 1 root root     1241 Aug 18 06:15 Test2.class
    -rw-r--r--. 1 root root      763 Aug 18 06:15 Test2$.class
    -rw-r--r--. 1 root root      245 Aug 18 06:15 test2.scala
    -rw-r--r--. 1 root root      486 Aug 18 10:23 test.scala
    • 在目录下看到两个编译后得到的文件,即Person.class和Person$.class。经 过编译后,伴生类和伴生对象在JVM中都被合并到了一起

    • 忽略Person$.class,只看Person.class。请使用下面命令进行“反编译”:

    [root@slave2 ~]# javap Person
    Compiled from "test.scala"
    public class Person {
    public static void main(java.lang.String[]);
    public static int newPersonId();
    public void info();
    public Person();
    public Person(java.lang.String);
    }

    应用程序对象

    • 每个Scala应用程序都必须从一个对象的main方法开始

    • 重新创建一个test.scala,在该文件中输入如下代码:

    • 为了运行下面的代码,我们现在可以使用两种不同的方法。

    • 第一种方法:scala test.scala

    object HelloWorld{
     def main(args: Array[String]): Unit = {
       println("hello , world!")
    }
    }
    • 第二种方法:先编译再执行

    [root@slave2 ~]# scalac test.scala 
    [root@slave2 ~]# ll
    total 32720
    -rw-------. 1 root root     1260 Jul  2 19:02 anaconda-ks.cfg
    -rw-r--r--. 1 root root 33485703 May 15 00:56 elasticsearch-5.5.2.tar.gz
    -rw-r--r--. 1 root root      580 Aug 18 10:34 HelloWorld.class
    -rw-r--r--. 1 root root      594 Aug 18 10:34 HelloWorld$.class
    -rw-r--r--. 1 root root       97 Aug 18 10:32 test.scala
    [root@slave2 ~]# scala HelloWorld
    hello , world!

    apply方法和update方法

    • 我们经常会用到对象的apply方法和update方法,虽然我们表面上并没有察觉,但是,实际上,在Scala中,apply方法和update方法都会遵循相关的约定被调用,约定如下:

      • 用括号传递给变量(对象)一个或多个参数时,Scala 会把它转换成对 apply方法的调用

      • 当对带有括号并包括一到若干参数的对象进行赋值时,编译器将调用 对象的update方法,在调用时,是把括号里的参数和等号右边的对象 一起作为update方法的输入参数来执行调用

    • 下面我们测试一下apply方法是否被调用,输入 以下代码:

    class Student {
     def apply(param: String): String={
       println("apply methon called , parameter is: " + param)
       "hello world!"
    }
    }
    object Student{
     def main(args: Array[String]): Unit = {
       val student = new Student()
       println(student("student"))
    }
    }
    //执行结果
    apply methon called , parameter is: student
    hello world!
    • 上面是类中定义了apply方法,下面看一个在单例对象中定义apply方法的例子:

    object Student{
     def apply(param1: String,param2: String): String={
       println("apply method called")
       param1 + "and" + param2
    }
     def main(args: Array[String]): Unit = {
       println(Student("zhangfei","liubei"))
    }
    }
    //执行结果
    apply method called
    zhangfeiandliubei
    • 下面我们测试一个伴生类和伴生对象中的apply方法实例,输入以下代码:

    class ApplyTest{
     def apply() ={
       println("apply method in class is called!")
    }
     def greetingOfClass:Unit={
       println("Greeting method in class is called.")
    }
    }
    object ApplyTest{
     def apply()={
       println("apply method in object is called!")
       new ApplyTest()
    }
    }
    object Student{
     def main(args: Array[String]): Unit = {
       val a = ApplyTest()
       a.greetingOfClass
       a()
    }
    }
    //执行结果
    apply method in object is called!
    Greeting method in class is called.
    apply method in class is called!
    • 从上面代码可以看出,当我们执行val a = ApplyTest()时,会导致apply方法的 调用并返回该方法调用的值,也就是ApplyTest的实例化对象。当执行a()时, 又会导致调用伴生类的apply方法,如果我们愿意,就可以在伴生类的apply方 法中写入一些处理逻辑,这样就可以把传入的参数赋值给实例化对象的变量。

    • 下面看一个apply方法的例子。由于Scala中的Array对象定义了apply方法, 因此,我们就可以采用如下方式初始化一个数组:

    val myStrArr = Array("bigdata","hadoop","spark")
    • 也就是说,不需要new关键字,不用构造器,直接给对象传递3个参 数,Scala就会转换成对apply方法的调用,也就是调用Array类的伴 生对象Array的apply方法,完成数组的初始化。

    • 实际上,update方法也是类似的,比如:

    val myStrArr = new Array[String](3) //声明一个长度为3的字符串数据,每个数组元素初始化为null
    myStrArr(0) = "bigdata" //调用了伴生类Array中的update方法,执行myStrArr.update(0,"bigdata")
    myStrArr(1) = "hadoop" //调用了伴生类Array中的update方法,执行myStrArr.update(1,"hadoop")
    myStrArr(2) = "spark" //调用了伴生类Array中的update方法,执行myStrArr.update(2,"spark")
    • 从上面可以看出,在进行元组赋值的时候,之所以没有采用Java中的方括 号myStrArr[0],而是采用圆括号的形式,myStrArr(0),是因为存在上述的 update方法的机制。

  • 相关阅读:
    uboot nand erase 的显示错误修复
    Sougo for linux install.
    S3C6410移植uboot2010.3(2)基本的启动信息修改
    S3C6410移植uboot2010.3(4)uboot的dnw功能添加
    S3C6410移植uboot2010.3(3)正常化配置
    ubuntu乱码修复
    应老婆点(20070705 13:11:34)(新浪)
    克己慎独 2008923 13:32:00 (21ic)
    信任(20061229 14:16:32)(新浪)
    不要轻易承诺 2008926 14:42:00 (21ic)
  • 原文地址:https://www.cnblogs.com/zxbdboke/p/10466299.html
Copyright © 2011-2022 走看看