Scala 一张图带你看懂什么是伴生对象

Posted 健哥说编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala 一张图带你看懂什么是伴生对象相关的知识,希望对你有一定的参考价值。

不得不说,Scala在数据封装上已经显示出它比Java的便捷。

1、类和对象

本节内容:

类、字段、方法。

 

1、类、字段和方法

定义一个类:

scala> class Stud{}

defined class Stud

使用new关键字,创建这个类对象:

scala> val stud = new Stud()

stud: Stud = Stud@5add7380

 

定义成员变量,如果没有使用修饰符号,则默认修饰符号为:public

scala> class Stud{

     |    var name=""

     | }

defined class Stud

创建这个对象:

scala> val stud = new Stud()

stud: Stud = Stud@4f6a5cc9

 

scala> stud.name="Jack"

stud.name: String = Jack

 

scala> println(stud.name)

Jack

成员变量必须要被赋值,否则将编译出错:

scala> class Stud{

     |    var name:String="" //这儿必须要赋值

     | }

defined class Stud

 

scala> val stud = new Stud();

stud: Stud = Stud@5776a9f8

 

scala> stud.name="Jery"

stud.name: String = Jery

 

或是声明变量的具体类型,如果没有声明类型则必须要通过=等于符号赋值,然后通过被赋的值,判断变量的类型:

scala> class Stud{

     |    var name:String=null;

     | }

defined class Stud

 

scala> val stud:Stud = new Stud();

stud: Stud = Stud@33602729

 

scala> stud.name="Jerry"

stud.name: String = Jerry

 

scala> println(stud.name)

Jerry

 

可以使用private关键字保护成员变量:

scala> class Stud{

     |   private var name:String="Jack"

     | }

defined class Stud

 

访问私有变量,可以提供些方法:

package cn.wangjian
object Demo01_Object {
  //object定义的main方法用于运行
  def main(args: Array[String]): Unit = {
    val stud: Stud = new Stud();
    stud.setName("Jack");
    println("name is:" + stud.getName());
  }
  class Stud {
    private var name: String = "";
    def setName(name: String): Unit = {
      this.name = name
    }
    def getName(): String = {
      //return关键字可以省略
      return this.name
    }
  }
}

 

注意:

1、上述中的参数变量name:Stringval类型,所以不能再被赋值。

2return语句可以省略,在scala中,默认最后一个表达式即为返回值。

 

以下是更简捷的方法:

package cn.wangjian
object Demo02_Field {
  def main(args: Array[String]): Unit = {
    val stud:Stud = new Stud();
    stud.setName("WangJian");
    println(stud.getName());
  }
  //以下是更快捷的方法
  class Stud {
    private var name: String = null;
    def setName(name: String):Unit = this.name = name;
    def getName(): String = this.name;
  }
}

 

2、类型推断和分号推断

方法的返回类型,scala可以自行推断:

 

Scala 一张图带你看懂什么是伴生对象

上面所示,在IDEAScala自动推断的返回类型是Int

尽管Scala可以自动推断类型,但还是建议给出具体的返回类型,正如以下代码所示:

 

Scala 一张图带你看懂什么是伴生对象

 

每一行语句最后的分号可以省略,但一行中包含多个语句时,分号则是必须的如:

val name:String = "Jerry";println(name);

 

3、单例对象

1Scala更面向对象,所以Scala的成员不允许有静态成员。

2:使用object关键字,用于定义一个单例的对象,而不是使用class关键字。

3:单例类必须要在同一个文件中定义类和类的伴生对象。

4Scala没有像Java那样的的静态类、静态成员、静态方法。但是Scala提供的object对象。这个Object类似于Java的静态类,它的成员、它的方法,默认都是静态的。

 

1object

示例1

package cn.wangjian
object Demo03_Object {
  def main(args: Array[String]): Unit = {
    println(Other.name);//由于Other类的name是静态的,所以可以直接调用
  }
  //使用Object定义一个类,里面的方法默认都是静态的
  object Other{
    var name:String="Jack";
  }
}

 

 

2、伴生对象与单例模式

1:如果有同样一个类与object名称完全一样,则这个类就是object的伴生类,相对的,object就类的伴生对象。

2:如果一个类有伴生对象,这个类,就可以通过object的名称访问到这个类的所有成员,但object不在此类的作用范围内。

所以声明scala单例对象的开过过程如下:

1:声明一个类,并使用private关键字,不允许其他对象实例化此类。即:class XXX private {  ...   }

2:声明伴生对象,并使用var声明伴生类的实例变量,并可以使用private关键字修饰。然后建议再创建一个方法叫instance()apply()返回这个成员变量的引用。

3:然后就可以在其他的方法中通过伴生对象引用单一伴生类的实例了。

package cn.wangjian
/**
  * 测试单例对象
  */
object Demo04_Singletone {
  def main(args: Array[String]): Unit = {
    val singletone: Singletone = Singletone.apply();
    singletone.setName("Jack");
    println(singletone.getName());
  }
  //定义类,将这个类定义成private,定义成private以后,其他对象将不能实例化这个对象,即不能new
  class Singletone private {
    private var name: String = _;
    private var age: Int = _;
    def setName(name: String): Unit = this.name=name;
    def getName(): String =this.name
  }
  //定义object对象
  object Singletone {
    /*这儿使用_下划线,表示赋值为变量的默认值,对于int默认值为0
    对于引用类型默认值为null,在其他运算中,下划线,表示当前对象自己*/
    private var  self: Singletone = _
    def apply(): Singletone = {
      if (self == null) {
        self = new Singletone()
        self
      } else {
        self
      }
    }
  }
}

一张图看懂Scala伴生对象实现的单例模式:

 

 

3、Scala应用程序

Scala应用程序是指包含main方法的程序。

1:只有使用object关键字声明的对象(类),才可以拥有main方法。

2Scala代码中,默认被导入的包是:java.lang.*scala._两个包和名为predef单例对象的所有成员。

即:

import scala._
import java.lang._
import scala.Predef._

3:在Predef中定义了包含Map,Set,String等等对象,所以在Scala程序中,可以直接使用。

4:在Predef中定义了很多有用的方法,如println就定义在Predef中。当调用println时,实际调用的是Predef.println方法。转而又调用了Console.println(..)方法。

5Scala的类或对象可以放到任意命名的scala文件中。但还是建议参考Java的做法,将类放到同名的文件中。

6scalac用于编译一个scala的源文件。

 

1、使用scalac编译scala源文件

对于开发完成的scala源文件,可以使用scala将它编译成java代码

以下是一个Scala的源文件:

Hello.scala文件:

package cn

object Hello{

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

println("Hello")

  }

}

 

然后使用scala编译上面的源代码:

D:\a>scalac Hello.scala

 

直接带包编译到目录下的文件为:

D:\a\cn

 

两个.classjava文件

如果对内部结构感兴趣,可以使用jdecompiler查看上面的字节码的源代码。

 

使用scala命令,运行编译的程序:

D:\a>scala cn.Hello

Hello

 

本质上来讲,可以使用scala命令直接运行一个.scala源文件,但这个源文件不能声明包:

所以,以下类可以直接通过scala运行,因为它没有声明包:

object Hello{

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

      println("HelloWorld")

   }

}

而以下类无法通过scala命令直接运行,必须要使用scalac编译以后才可以运行:

因为它有包:

package cn

object Hello{

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

println("Hello")

  }

}

 

2、APP

也可以直接使用app类开发应用程序,APP类中已经包含了main函数,直接继承App类然后开发需要的代码即可:

package cn.wangjian
/**
  * 另一种开发APP的方法
  */
object Demo05_App extends App {
  println("参数的个数:"+args.length)
  for(arg<-args){
    println(arg)
  }
  println("遍历完成")
}


以上是关于Scala 一张图带你看懂什么是伴生对象的主要内容,如果未能解决你的问题,请参考以下文章

scala伴生类和伴生对象的理解

Scala编程之伴生对象

Scala伴生对象

通过 Java 反射找到 Scala 类型的伴生对象的可靠方法是啥?

通过 Java 反射找到 Scala 类型的伴生对象的可靠方法是啥?

scala 单例伴生对象伴生类