Programming In Scala笔记-第四章、类和对象
类似于Java,Scala中也有类和对象的概念。
一、类、属性和方法
1、类
类是对一类事物的抽象,当一个类被定义后,就可以以该定义为模板,定义该类的一系列对象。比如说有以下一个模板
人类:
有姓名;
有一个大脑;
有四肢;
有性别;
会思考;
有语言能力;
上面这个模板可以认为是对正常人类的一个最简单的抽象,那么有两个人张三和李四,就是人类这一模板的具体实例了。
在Scala中,用class关键字定义一个类,用new关键字实例化该类的一个对象。一个简单的类定义和实例化如下所示
class ChecksumAccumulator {
// 具体定义代码省略
}
new ChecksumAccumulator
在上面代码中省略的部分可以写入一些该类的属性和方法。所谓属性是指该类的一些特性,比如上面例子中的姓名,性别等,都可以认为是人类的一个属性。而方法是指该类可以执行的一些逻辑片段,比如上面例子中定义人类的走路方式为站立行走,那么正常的两个人类张三和李四的行走方式都是站立行走了。
有关类的属性和方法,接下来再进行分析。
2、属性
属性可以用var和val来定义,比如
class ChecksumAccumulator {
var sum = 0
}
那么,使用下面代码new出两个对象
val acc = new ChecksumAccumulator
val csa = new ChecksumAccumulator
acc和csa都有一个属性sum。并且值都是0。如下图所示,前面两个圆圈表示acc和csa对象的具体存储,指向同一个0是由于0在常量池中只有一个。
执行acc.sum=3可以将acc的sum属性更新为3,那么现在的情况是这样的
从这里可以看出,虽然acc是以val来定义的,但是可以修改其中的属性值。定义为val的作用是,如果将acc指向另一个ChecksumAccumulator对象时就会报错了。一般来说,最好将属性定义为private类型,private类型的属性,只能由该类中的方法进行访问和修改,尽量避免外部代码直接修改对象的属性值。如果需要属性发生变化,可以通过方法来实现。
3、方法
方法以def开头,里面包含了一段可执行的代码片段。这里需要注意的是,方法的参数是val类型的,如果在代码中更改参数值,是会报错的。
class ChecksumAccumulator {
private var sum = 0
def add(b: Byte): Unit = {
sum += b
}
def checksum(): Int = {
return ~(sum & 0xFF) + 1
}
}
上面代码中定义了两个方法,根据这两个方法的定义,可以进行一定的简化,
class ChecksumAccumulator {
private var sum = 0
def add(b: Byte): Unit = sum += b
def checksum(): Int = ~(sum & 0xFF) + 1
}
上一篇博客中提到过,返回值为Unit的语句,会产生side effects。这里add方法的side effects是改变了sum变量的值。side effects产生的影响,要么是改变了某个mutable变量的值,要么是产生了一些I/O,这些并不会影响其他代码的执行。
对于这种返回值为Unit的方法,可以去掉前面的Unit =部分,将函数体用花括号包起来。
class ChecksumAccumulator {
private var sum = 0
def add(b: Byte) { sum += b }
def checksum(): Int = ~(sum & 0xFF) + 1
}
上面代码中add方法的写法,即使其执行逻辑的返回值不为Unit,这种写法也显示的将该方法返回值设置为Unit了。
二、语句划分
不知道有没有发现在上面的代码中并不像Java代码那样,每一句代码的结尾用分号进行分割。在Scala中每一行语句的结尾并不需要写一个分号,一般情况下,以换行作为默认的分隔符。只有当一行中写多句代码时,代码之间才需要以分号进行分隔。
val s = "hello"; println(s)
Scala默认换行为代码直接的分隔符,
x
+ y
会被认为是两行代码,x和+ y。但是如果确实同一句代码需要换行应该怎么办?可以用圆括号将同一句代码包围起来,在圆括号中可以使用换行。
(x
+ y)
其实就是x + y的换行形式。
三、单例对象
虽然Scala是函数式编程语言,但是说到面向对象,其实Scala比Java还严格。在Java中,一个类还可以有一些静态属性或者静态方法,这样在不new一个对象时,也可以使用其中很多的静态属性和方法。但是Scala没有静态属性和方法一说,任何属性和方法的使用,都是通过对象来进行的。
如果确实需要在Scala中直接使用类名调用属性和方法应该怎么做?Scala通过提供一种单例对象,或者说伴生对象巧妙的实现了这一功能。前面我们定义了一个ChecksumAccumulator类,我们用另一个关键字object,同样使用ChecksumAccumularot这个名字,就生成了一个ChecksumAccumulator类的伴生对象了。
import scala.collection.mutable.Map
object ChecksumAccumulator {
private val cache = Map[String, Int]()
def calculate(s: String): Int =
if (cache.contains(s))
cache(s)
else {
val acc = new ChecksumAccumulator
for (c <- s)
acc.add(c.toByte)
val cs = acc.checksum()
cache += (s -> cs)
cs
}
}
接下来我们就可以使用ChecksumAccumulator.calculate直接进行计算了。从字面上看,和Java中调用静态方法是一样的。
上面的ChecksumAccumulator对象称为ChecksumAccumulator类的伴生对象,ChecksumAccumulator类称为ChecksumAccumulator对象的伴生类。伴生对象和伴生类,需要写在同一个源文件中,并且伴生类和伴生对象之间可以互相访问对方的private成员。
四、代码运行的入口
在Java中,一个Application是以某个Class中的public static void main(String[] args)的方法开始的。想要运行一段Scala代码,需要定义一个单例对象,并且在该单例对象中写一个main方法,这个方法接收的参数是一个String类型数组,返回值类型为Unit。
import ChecksumAccumulator.calculate
object Summer {
def main(args: Array[String]) {
for (arg <- args)
println(arg +": "+ calculate(arg))
}
}
一个object中的main方法,是一个Application的入口。类似于java中的main方法。
不过Scala也提供了一个名为Application的trait,可以简单的把trait理解成Java中的接口。如果object继承自该trait的话,那么不需要main方法也能运行起来。把原来需要写在main方法中的代码,直接写在随后的花括号中。
import ChecksumAccumulator.calculate
object FallWinterSpringSummer extends Application {
for (season <- List("fall", "winter", "spring"))
println(season + " : " + calculate(season))
}
这段代码之所以能够运行,从Application中可以看到,这里面已经实现了一个main方法。上面写的这些代码,在这个类被初始化时由主构造方法执行。
Programming In Scala笔记-第四章、类和对象的更多相关文章
- Programming In Scala笔记-第六章、函数式对象
这一章主要是以定义和完善一个有理数类Rational为线索,分析和介绍有关类定义,构造函数,方法重写,变量定义和私有化,以及对操作符的定义等. 一.Rational类定义和构造函数 1.定义一个空类 ...
- Programming In Scala笔记-第十一章、Scala中的类继承关系
本章主要从整体层面了解Scala中的类层级关系. 一.Scala的类层级 在Java中Object类是所有类的最终父类,其他所有类都直接或间接的继承了Object类.在Scala中所有类的最终父类为A ...
- java面向对象编程——第四章 类和对象
OO:面向对象 OOP:面向对象编程 OOA:面向对象分析 OOD:面向对象设计 结构化编程:从顶向下,将一个大问题分解成更小的任务,然后为每一个更小的任务编写一个过程.最后程序员会编写一个主过程来启 ...
- Java学习笔记【四、类、对象、接口】
编程语言的发展 机器语言 过程语言 面向对象编程--封装.继承.多态 关键字 extends implements override overload super this static abstra ...
- Programming In Scala笔记-第十七章、Scala中的集合类型
本章主要介绍Scala中的集合类型,主要包括:Array, ListBuffer, Arraybuffer, Set, Map和Tuple. 一.序列 序列类型的对象中包含多个按顺序排列好的元素,可以 ...
- Programming In Scala笔记-第七章、Scala中的控制结构
所谓的内建控制结构是指编程语言中可以使用的一些代码控制语法,如Scala中的if, while, for, try, match, 以及函数调用等.需要注意的是,Scala几乎所有的内建控制结构都会返 ...
- Programming In Scala笔记-第五章、Scala中的变量类型和操作
这一章的一些基础性的东西,主要包括Scala中的基本变量类型,以及相关的一些操作符. 一.简单类型 下表中列出Scala语言中的基本类型,以及其字节长度,其中Byte, Short, Int, Lon ...
- The C++ Programming Language 学习笔记 第四章 类型和声明
1.关于main 函数中的 return 0 C99标准中,main 函数的返回值类型必须是 int ,这样返回值才能传递给程序的激活者(如操作系统).如果 main 函数的最后没有写 return ...
- scala编程(四)——类和对象
类,字段和方法 在scala里定义一个典型的类,代码如下: class ChecksumAccumulator { private var sum = 0 def add(b: Byte): Uni ...
随机推荐
- MySQL查询机制
在MySQL中,每当查询被发送到服务端时,服务器在执行语句之前将会进行下面的检查: 用户是否有权限执行该语句? 用户是否有权限访问目标数据? 语句的语法是否正确 如果查询通过了这三个测试,就会被传递给 ...
- 在 .NET Core 中使用 DiagnosticSource 记录跟踪信息
前言 最新一直在忙着项目上的事情,很久没有写博客了,在这里对关注我的粉丝们说声抱歉,后面我可能更多的分享我们在微服务落地的过程中的一些经验.那么今天给大家讲一下在 .NET Core 2 中引入的全新 ...
- java四种访问控制权限:public ,default,protected,private
四种访问权限的控制 范围 private default protected public 同一个类中 √ √ √ √ 相同包不同类 × √ √ √ 不同包的子类中 × × √ √ 不同包非子类 × ...
- mysql sql语句执行时是否使用索引检查方法
在日常开发中,使用到的数据表经常都会有索引,这些索引可能是开发人员/DBA建表时创建的,也可能是在使用过程中新增的.合理的使用索引,可以加快数据库查询速度.然而,在实际开发工作中,会出现有些sql语句 ...
- 实验吧_拐弯抹角(url伪静态)&Forms
拐弯抹角 先贴代码 <?php // code by SEC@USTC echo '<html><head><meta http-equiv="chars ...
- Fetching data with Ajax小例子
ajax获取数据示例: 示例1 通过ajax获取txt文件里面的内容示例: <html> <head> <title>Ajax at work</title& ...
- 【SDOI2009】学校食堂
Description 小F的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用 ...
- Simpson积分(BZOJ2178)
lrj的代码常数太大T了QAQ,改了一下. #include <cstdio> #include <cmath> #include <algorithm> usin ...
- FreeMarker学习教程
copy自http://demojava.iteye.com/blog/800204 以下内容全部是网上收集: FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主 ...
- JVM Class详解之一
首先看Class中包含哪些信息简单的说所有Java文件中有的信息class文件都有,编译器帮我们将java文件转化成了JVM能看懂的class格式而已 Class 概述 Class文件是一组以8位字节 ...