Scala学习(六)对象

Scala中对象本质上能够拥有类的全部特质,甚至能够扩展其余类或特质。但有一个例外:你不能提供构造器参数java

1.单例对象

在Scala中没有静态方法和静态字段,可是咱们能够用object语法来达到相同的目的。对象定义了某个类的单个实例:数组

object Util{

    private val str = "Hello World";

    def out(){

        println(str); 

    }

}

在解释器中运行:app

能够看到,其效果与Java中的静态方法同样。this

对象的构造器在该对象第一次被使用时调用。若是一个对象从未被使用,器构造器也不会执行。spa

注:Scala的编译器能够编译txt格式的scala代码。scala

那么,为何object能够有这样相似于Java中的静态的效果呢?咱们来看下Util对象编译后的class文件:code

咱们将Util对象的代码进行编译,以后生成了两个class文件Util.class 和 Util$.class ,咱们分别查看他们都是什么:对象

首先Util.class中咱们看到有一个静态方法out继承

Util$.class是一个单例模式的类,里面有咱们Scala的Util对象的str成员,因为str为val,因此Util$.class这里只有str的读方法str()编译器

咱们来反编译Util.class与Util$.class,这样能够更加直观

这里Util.class的out()方法调用Util$.class的out()方法

注:Scala的对象编译完成后,会生成对应的Java class。其中方法都是静态方法,非静态成员对应到生成的单例类中。

说明:由于Scala对象是单例的这一特性,所以在程序中任何须要使用单例的地方,你均可以用Scala对象实现。

经过上面一系列的分析,咱们清楚了Scala如何经过对象,来实现Java中静态变量的效果,由于他的底层就是经过java的静态方法实现的。

2.伴生对象

在Java或C++中,你一般会用到既有静态放大又有普通方法的类。在Scala中,你能够经过类和与类同名的“伴生对象”来达到相同的目的。

伴生对象要求类名和object名称相同,而且在同一个Scala文件中定义。

咱们来定义一个伴生对象:

class Car{
    def stop(){
        println("stop...");
    }
}

object Car{
    def run(){
        println("run...")
    }
}

接下来咱们分别执行类的方法和伴生对象的方法,对比差别。

咱们看到伴生对象中的run()方法能够不用实例化直接运行(那固然,他是静态的方法),二类中的stop()方法不能直接运行,须要先实例化才能运行。

接下来咱们看下上面的代码编译后是什么结构。

一样生成了Car.class与Car$.class,咱们分别用javap命令看下这两个class的结构

在Car.class中出现了两个方法,一个是静态方法run(),也就是咱们在伴生对象中定义的方法。另外一个是普通方法stop(),使咱们在类中定义的方法

Car$.class仍是一个单例,因为咱们的代码中没有定义普通成员,所以这里很干净。

反编译class文件:

说明:伴生对象能够被访问,但并不在做用于当中。举例来讲,类中必须经过 对象名.方法 的方式去访问,而不是直接调用对象名。

3.扩展类或特质的对象

给个人感受就是Java中的继承。下面来用代码演示对象扩展类(对象同样):

咱们定义了一个抽象的Animal类 和一个 继承了Animal类的对象Dog,Dog重写了Animal类中的未定义方法。

上面的演示咱们得知:

  1. Scala中抽象类的定义和Java同样用abstract关键字,继承和Java同样用extends关键字
  2. 和Java同样抽象类不能被实例化

4.apply方法

咱们一般会在对象中定义一个apply方法。当余姚以下表达式时,apply方法就会被调用:

Object(参数1...参数N)

一般,这样一个Apply方法返回的是一个伴生对象。

举例来讲,Array数组对象定义了apply方法,让咱们能够以这样的表达式返回一个数组对象

Array(1,2,3,4,5)

为何不用关键字呢?由于对于嵌套表达式而言省去new关键字会方便不少,例如:

Array(Array(1,2),Array(2,3))

注意:Array(100)和new Array(100)很容易搞混。前一个表达式时调用了apply方法,返回了一个单元素(整数100)的Array[Int];而第二个表达式调用的是构造器this(100),结果是Array[Nothing],包含100个null元素

apply方法须要定义在对象中,若是类须要定义apply方法,则须要定义在它的伴生对象中。

5.应用程序对象

每一个Scala程序都必须从一个对象的main方法开始,这个方法的类型为Array[String] => Unit:

object Hello{

    def main(args: Array[String])  {

        println("Hello World")

    }

}

因为Java中main是静态的方法,所以Scala中的main方法必须定义在对象中或伴生对象中。

将上面的代码编译后执行:

或者直接运行scala文件

Scala中除了使用main方法外,还有另外一种方式实现相同的功能,经过扩展App特质,将代码写入构造方法体内:

object Hello extends App{
    println("Hello World")
}

再次编译效果相同

6.枚举

和Java或C++不一样,Scala中并无枚举类型。不过标准类库提供了一个Enumeration助手类,能够用于产出枚举。

咱们能够经过下面3种方式构造枚举:

//统一构建

object MyEnum extends Enumeration{
    val Red,Yellow,Green = Value
}

//与上面同样,只不过度开写

object MyEnum extends Enumeration{
    val Red = Value;
    val Yellow = Value;
    val Green = Value;
}

//Value方法是一个重载方法,能够经过它定义枚举值得id,对应值等

object MyEnum extends Enumeration{
    val Red = Value(0,"red");//设置枚举的id和对应值
    val Yellow = Value(10);//设置枚举的id,值默认与成员同名
    val Green = Value("gre");//设置枚举对应值,id默认前一个枚举的id+1
}

定义完成后,咱们就能够用MyEnum.Red、MyEnum.Yellow来引用枚举值了。

注:枚举的类型是MyEnum.Value而不是MyEnum,后者是握有这些值的对象。

有人推荐引入一个类型别名,不过这样须要与import一块儿用才会有意义:

object MyEnum extends Enumeration{

    type MyEnum = Value
    val Red,Yellow,Green = Value
}

import MyEnum._

def doWhat(color:MyEnum) = {

    if(color == Red) "stop"

    else "go"

}

枚举值得ID能够经过方法id返回,名称经过toString方法返回。

经过values方法返回枚举值的集合:

for(c <- MyEnum.values) println(c.toString + " " + c.id)

最后你能够经过ID或者名称来进行查找定位枚举值对象:

MyEnum(0)

MyEnum.withName("Red")

相关文章
相关标签/搜索