对象

单例对象

  • 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. (轉)EasyUI - DataGrid 去右边空白滚动条列

    熟悉 EasyUI - DataGrid 的童鞋应该会注意到这样一个情景: 想去掉这块,找了下资料,发现也有人同样纠结:http://www.cnblogs.com/hantianwei/p/3440 ...

  2. [RF] 安装好Robot Framework之后怎样让启动的界面后面不带命令行窗口,且图片以机器人显示

    安装好Robot Framework之后,通过 C:\Python27\Scripts\ride.py 启动时会带上一个命令行窗口: 怎样让启动的界面后面不带这个命令行窗口,且图片以机器人显示? 方法 ...

  3. Sliding Window Median LT480

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  4. R.java的生成规则

    0x7f010000 开头的是attr 0x7f050000 开头的是anim 0x7f0b0002 开头的是bool 0x7f020000 开头的是drawable 0x7f060000 开头的是i ...

  5. sql2005性能优化(在32位系统上突破2G内存使用量的方法) .

    转载自http://blog.csdn.net/soldierluo/article/details/6589743 服务器磁盘为(SAS)IBM组成RAID0+1,SQL2K5只识别4G内存,实际只 ...

  6. WPF禁止拖拽窗口到边缘自动最大化

    近期有个需求,可以通过拖拽改变窗口大小,但是不允许窗口最大化.最小化.拖到边缘的时候也不能自动最大化. 要想禁止拖拽窗口到边缘自动最大化,只要改注册表即可,但是系统所有应用都会被禁止. 1.运行reg ...

  7. python console 设立快捷键 学习源码 用到英语

    arbitrary---随意 iterable----迭代 invalid syntax   -----无效的语法 subscriptable   ----可索引访问的

  8. 5. Sports 体育运动

    5. Sports 体育运动 (1) Sport is not only physically challenging,but it can also be mentally challenging. ...

  9. nxn随机矩阵乘以概率向量依旧是概率向量

    由上面可进一步推到出A*A是随机矩阵看成(A a1,A a2...A an) 所以A^m依然是随机矩阵.

  10. ubuntu彻底删除apache2 再重装

    删除apache2不彻底,导致用 apt-get install apache2 重新装时总是不成功.下面是如何彻底删除apache2 1. 删除apache 代码: $ sudo apt-get - ...