对象

单例对象

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

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

object Person{
 private var lastId = 0
 def newPersonId()={
   lastId += 1
   lastId
}
}
printf("The first person id is %d.\n" , Person.newPersonId())
printf("The Second person id is %d.\n" , Person.newPersonId())
printf("The Third person id is %d.\n" , 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.\n" , 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.\n" , 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方法的机制。

Scala_对象的更多相关文章

  1. Scala_类和对象

    类是对象的抽象,而对象是类的具体实例.类是抽象的,不占用内存,而对象是具体的,占用存储空间. import scala.beans.BeanProperty class ChecksumAccumul ...

  2. Scala_单例对象

    在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object. 对象的无参构造器在第一次使用时被调用,且单例对象没有有残构造器. Enu ...

  3. 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑

    阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...

  4. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  5. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  6. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  7. JS核心系列:浅谈原型对象和原型链

    在Javascript中,万物皆对象,但对象也有区别,大致可以分为两类,即:普通对象(Object)和函数对象(Function). 一般而言,通过new Function产生的对象是函数对象,其他对 ...

  8. Chrome出了个小bug:论如何在Chrome下劫持原生只读对象

    Chrome出了个小bug:论如何在Chrome下劫持原生只读对象 概述 众所周知,虽然JavaScript是个很灵活的语言,浏览器里很多原生的方法都可以随意覆盖或者重写,比如alert.但是为了保证 ...

  9. XStream将java对象转换为xml时,对象字段中的下划线“_”,转换后变成了两个的解决办法

            在前几天的一个项目中,由于数据库字段的命名原因 其中有两项:一项叫做"市场价格"一项叫做"商店价格" 为了便于区分,遂分别将其命名为market ...

随机推荐

  1. OKI系列针式打印机更换色带图解教程

    色带一直换不好,今天找到一个带图的教程,收藏一下 打开新色带的包装后,我们可以仔细观察一下新色带,找到里面带有一段“扭曲”色带的位置,这段色带就是:“莫比乌斯带”结构. 找到“莫比乌斯带”结构(就是有 ...

  2. 冒泡排序(js版)

    基本思想:两两比较相邻记录的关键字,如果反序则交换,直至没有反序为止. 最初的冒泡排序(初级版): //从小到大 function BubbleSort(arr){ var i,j,temp; for ...

  3. 解决Address is in use:Windows和Linux通过杀死进程

    在开发无卡支付系统的过程中,因为用了端口来监听服务,在调试程序的时候,忘了关,再次运行的时候会出现Address is in use的问题,即端口已经被绑定,无法再次使用,最直观的方法就是杀死之前的进 ...

  4. JDK 之 NIO 2 WatchService、WatchKey(监控文件变化)

    JDK 之 NIO 2 WatchService.WatchKey(监控文件变化) JDK 规范目录(https://www.cnblogs.com/binarylei/p/10200503.html ...

  5. SSH无法连上CentOS7的问题

    今天安装完带GNOME的CentOS后发现XShell无法连接上Linux. 原因是sshd服务没有开启.下面是解决办法: 1 ip addr 发现网卡名称为ens33 2 在/etc/sysconf ...

  6. SVN基本操作 (zz)

    SVN基本操作 分类: LINUX 原文地址:SVN基本操作 作者:tuyer 文章摘要:SVN 基本操作:SVN是什么 Svn是一个离线的代码管理,可以多个人一起修改,然后再将修改的内容提交到Svn ...

  7. win8 本地化

    先看个简单的案例:新时尚Windows8开发(6):资源 & 本地化 http://www.silverlightchina.net/html/windows8/study/2012/0902 ...

  8. unity技巧

    在之前的程序编写过程中,虽然对相关的方法进行了实例化,但是在运行的时候总是会出现“未将对象引用设置到对象的实例”,出现该种问题的原因是由于在实例化后,没有对实例化进行引用赋值,所以导致相关变量无法在其 ...

  9. java常用设计模式总览

    一.java的设计模式大体上分为三大类: 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式. 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组 ...

  10. TCP粘包问题分析和解决(全)

    TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...