快学Scala-第五章 类
知识点:
1.简单类和无参方法
class Counter {
private var value = 0 //必须初始化字段
def increment() { value += 1} //方法默认是公有的
def current() = value
}
在Scala中,类并不声明为public,Scala源文件可以包含多个类,所有这些类都具有共有可见性。
val myCounter = new Counter //or new Counter()
myCounter.increment()
println(myCounter.current())
调用无参方法,可以写上圆括号,也可以不写。对于改值器方法(即改变对象状态的方法)使用(),对于取值器方法(不会改变对象状态的方法)去掉().可以通过以不带()的方式声明current来使用不带圆括号的风格。
2.带gettter和setter的属性
Scala生成面向JVM的类,对于声明的字段都会提供getter和setter方法。在Scala中,getter和setter分别叫做age和age_=,可以重新定义getter和setter方法。
- 对于私有字段而言,getter和setter方法也是私有的;
- 如果字段是val, 则只有getter方法被生成;
- 如果你需要任何getter和setter,可以将字段声明为 private[this].
颇具影响的Eiffel语言的发明者Bertrand Meyer提出了“ 统一访问原则”:某个模块提供的所有服务都应该能通过统一的表示法访问到,至于它们是通过存储还是通过计算来实现的,从访问方式上应无从可知。Scala符合这个原则。
3.只带getter的属性
如果属性的值在对象构建完成后不再改变,则可以使用val字段,scala会生成一个私有的final字段和getter方法。总结一下,在实现属性时有如下四个选择:
- var foo: Scala自动合成一个getter和setter方法
- val foo: Scala自动合成一个getter
- 由你来定义foo和foo_=方法
- 由你来定义foo方法
当你在Scala类中看到字段的时候,它代表的是一个私有字段加上getter方法(对val字段)或者getter和setter方法(对var字段而言)。
4.对象私有字段
private[this]修饰字段时,表明某个对象.value这样的访问不被允许。类定义的方法只能访问到当前对象的value字段,而不能访问同样类的其他对象的字段,这样的访问被称为对象私有的。
对于类私有的字段,Scala生成私有的getter和setter方法,而对于对象私有的字段,Scala不会生成getter和setter方法。
5.Bean属性
将Scala字段标注为@BeanProperty时,会自动生成getFoo/setFoo这样的方法。
Scala字段 | 生成的方法 | 何时使用 |
val/var name | 公有的name name_=(仅限于var) |
实现一个可以被公开访问并且背后是以一个字段形式保存的属性 |
@BeanProperty val/var name | 公有的name getName() name_=(仅限于var) setName(…) (仅限于var) |
与JavaBean互操作 |
private val/var name | 私有的name name_=(仅限于var) |
用于将字段访问限制在本类的方法,就和Java一样,尽量使用private——除非你真的需要一个公有的属性 |
private[this] val/var name | 无 | 用于将字段访问限制在同一个对象上调用的方法,并不经常用到 |
private[类名] val/var name | 依赖于具体实现 | 将访问权赋予外部类,不经常用到 |
6.辅助构造器
1)辅助构造器的名称为this
2)每一个辅助构造器都必须以一个对先前已定义的其他辅助构造器或猪狗在其的调用开始。
如果没有显示定义主构造器则自动拥有一个无参的主构造器。
class Person{
private var age = 0
private var name = "" def this(name:String){
this()
this.name=name
} def this(name:String,age:Int){
this(name)
this.age = age
}
}
7.主构造器
1)主构造器的参数直接放置在类名后
2)主构造器会执行类定义中的所有语句
如果类名之后没有参数,则该类具备一个无参主构造器。通常可在主构造器中使用默认参数来避免过多的使用辅助构造器。构造参数可以是普通的方法参数,不带val或var,这样的参数如何处理取决于它们在类中如何被使用。如果不带val或var的参数至少被一个方法所使用,它将被升格为字段;否则,该参数将不被保存为字段,仅仅是一个可以被主构造器中的代码访问的普通参数。
class Person(name:String,age:Int){
def description = name + " is " + age + " years old"
}
//声明和初始化了不可变字段name、age,这两个字段都是对象私有的,等同于private[this] val字段的效果
针对主构造器参数生成的字段和方法
主构造器参数 | 生成的字段/方法 |
name: String | 对象私有字段,如果没有方法使用那么,则没有该字段 |
private val/var name: String | 私有字段,私有的getter/setter方法 |
val/var name: String | 私有字段,公有的getter/setter方法 |
@BeanProperty val/var: String | 私有字段,公有的Scala版和JavaBean版的getter/setter方法 |
8.嵌套类
在Scala中,几乎可以在任何语法结构中内嵌任何语法结构,在任何函数中定义函数,在类中定义类。
练习:(参考网址)
1.改进5.1节的Counter类,让它不要在Int.MaxValue时变成负数
class Counter {
private var value = 0 //必须初始化字段
def increment() {
if(value < Int.MaxValue){
value += 1
}
else value } //方法默认是公有的
def current() = value
}
2.编写一个BankAccount类,加入deposit和withdraw方法,和一个只读的balance属性
class BankAccount{
val balance = 0
def deposit(amount:Double) {}
def withdraw(){}
}
3.编写一个Time类,加入只读属性hours和minutes,和一个检查某一时刻是否早于另一时刻的方法before(other:Time):Boolean。Time对象应该以new Time(hrs,min)方式构建。其中hrs以军用时间格式呈现(介于0和23之间)
class Time(val hours:Int,val minutes:Int){ def before(other:Time):Boolean={
hours < other.hours || (hours == other.hours && minutes < other.minutes)
} override def toString():String={
hours + " : " + minutes
}
}
4.重新实现前一个类中的Time类,将内部呈现改成午夜起的分钟数(介于0到24*60-1之间)。不要改变公有接口。也就是说,客户端代码不应因你的修改而受影响
class Time(val hours:Int,val minutes:Int){ def before(other:Time):Boolean={
hours < other.hours || (hours == other.hours && minutes < other.minutes)
} override def toString():String={
(hours * 60 + minutes)+""
}
}
5.创建一个Student类,加入可读写的JavaBeans属性name(类型为String)和id(类型为Long)。有哪些方法被生产?(用javap查看。)你可以在Scala中调用JavaBeans的getter和setter方法吗?应该这样做吗?
import scala.beans.BeanProperty
//答案里导入的包 scala2.11.8没有这个类了,在API中查找包位置
class Student {
@BeanProperty var name:String = _
@BeanProperty var id:Long = _
}
javap –c Student 查看 生成了name()\name_=\setName()\getName() id()\id_=\setId()\getId()
Compiled from "Student.scala"
public class Student {
public java.lang.String name();
Code:
0: aload_0
1: getfield #15 // Field name:Ljava/lang/String;
4: areturn public void name_$eq(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #15 // Field name:Ljava/lang/String;
5: return public void setName(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #15 // Field name:Ljava/lang/String;
5: return public long id();
Code:
0: aload_0
1: getfield #24 // Field id:J
4: lreturn public void id_$eq(long);
Code:
0: aload_0
1: lload_1
2: putfield #24 // Field id:J
5: return public void setId(long);
Code:
0: aload_0
1: lload_1
2: putfield #24 // Field id:J
5: return public java.lang.String getName();
Code:
0: aload_0
1: invokevirtual #30 // Method name:()Ljava/lang/String;
4: areturn public long getId();
Code:
0: aload_0
1: invokevirtual #33 // Method id:()J
4: lreturn public Student();
Code:
0: aload_0
1: invokespecial #37 // Method java/lang/Object."<init>":
()V
4: return
}
6.在5.2节的Person类中提供一个主构造器,将负年龄转换为0
class Person(var age:Int){
age = if(age < 0) 0 else age
}
7.编写一个Person类,其主构造器接受一个字符串,该字符串包含名字,空格和姓,如new Person("Fred Smith")。提供只读属性firstName和lastName。主构造器参数应该是var,val还是普通参数?为什么?
val,如果为var的话,对应的字符串有get和set方法,因为只提供只读属性firstName和lastName,不能重复赋值。
8.创建一个Car类,以只读属性对应制造商,型号名称,型号年份以及一个可读写的属性用于车牌。提供四组构造器。每个构造器fc都要求制造商和型号为必填。型号年份和车牌可选,如果未填,则型号年份为-1,车牌为空串。你会选择哪一个作为你的主构造器?为什么?
class Car(val maker:String,val typeName:String){
辅助构造器参数分别为 型号年份、车牌、型号年份和车牌,不知道对不。
9.考虑如下的类
class Employ(val name:String,var salary:Double){
def this(){this("John Q. Public",0.0)}
}
重写该类,使用显示的字段定义,和一个缺省主构造器。你更倾向于使用哪种形式?为什么?
class Employ{
val name:String = "John Q. Public"
var salary:Double = 0.0
}
2
快学Scala-第五章 类的更多相关文章
- 快学Scala 第6章 对象 - 练习
1. 编写一个Conversions对象,加入inchesToCentimeters.gallonsToLiters和milesToKilometers方法. object Conversions { ...
- 快学Scala 第五课 (构造映射,获取映射值,更新映射值,迭代映射,与Java互操作)
构造映射: val score = Map[String, Int]() val score1 = HashMap[String, Int]() val value1 = Map[String, In ...
- 《快学Scala》第二章 控制结构和函数
- 《快学Scala》第一章 基础
- 快学Scala习题解答—第一章 基础
1 简介 近期对Scala比较感兴趣,买了本<快学Scala>,感觉不错.比<Programming Scala:Tackle Multi-Core Complexity on th ...
- 《快学Scala》
Robert Peng's Blog - https://mr-dai.github.io/ <快学Scala>Intro与第1章 - https://mr-dai.github.io/S ...
- 快学Scala 第十九课 (trait的abstract override使用)
trait的abstract override使用: 当我看到abstract override介绍的时候也是一脸懵逼,因为快学scala,只介绍了因为TimestampLogger中调用的super ...
- 简学Python第五章__模块介绍,常用内置模块
Python第五章__模块介绍,常用内置模块 欢迎加入Linux_Python学习群 群号:478616847 目录: 模块与导入介绍 包的介绍 time &datetime模块 rando ...
- [Scala] 快学Scala A2L2
集合 13.1 集合的三大类 所有的集合都扩展Iterable特质.集合的三大集合为Seq, Set, Map Seq是一个有先后次序的值的序列,比如数组或列表.IndexSeq允许我们通过整型下表快 ...
- 《快学Scala》——控制结构和函数
条件表达式 在Scala中if/else表达式有值,这个值就是跟在if或else之后的表达式的值.例如: if (x > 0) 1 else -1 上述表达式的值是1或-1,具体是哪一个取决于x ...
随机推荐
- debian服务器上不了网,缺少默认网关
debian服务器上不了网,缺少默认网关 root@hbg:/# route -nKernel IP routing tableDestination Gateway Genm ...
- 垂直分割群集模型与多通道引擎 -- ESFramework 4.0 进阶(10)
在ESFramework 4.0 进阶(09)-- ESPlatform 支持的三种群集模型一文中,我们介绍了ESPlatform支持的三种群集模型 -- 垂直分割模型.水平分割模型.交叉模型.我们看 ...
- LightOJ 1337 F - The Crystal Maze (bfs)
Description You are in a plane and you are about to be dropped with a parasuit in a crystal maze. As ...
- onmousedown活用之碰撞效果
通过绝对定位,在页面中随意位置设置两个div; 也就是说div 是拖动的框,div1和div2是被触碰的框; <!DOCTYPE html> <html> <head&g ...
- 网页 HTML表单
今天,我首先先学习了图片热点和在原来页面嵌入其他页面. 图片热点:<img src="" usemap="#ditu"/> <map name ...
- shell编程之sed
一.sed (Stream Editor) 1.定位行:sed -n '12,~3p' pass #从第12行开始,直到下一个3的倍数行(12-15行)sed -n '12,+4p' pass #从第 ...
- 一些常用数据库操作在mysql及sql server中实现方式的差异
因为本文强调的是不同点,所以先讲述不同点,再讲相同点. 一.不同点 1.创建表时主键id的自增实现方式不一样 mysql数据库的实现方式是auto_increment,示例如下 CREATE TABL ...
- LoadRunner学习知多少--IP欺骗使用
使用IP欺骗功能时,需要将系统防火墙,杀毒软件关闭(如果有影响的话) 一.为什么要设置IP欺骗 1. 当某个IP的访问过于频繁,或者访问量过大时,服务器会拒绝访问请求,这时候通过IP欺骗可以增加访问频 ...
- LINUX修改IP地址
以前都是使用自动IP动态分配获取IP的,虽然每次获得的ip都是相同的,但我还是决定自己设置一个IP.输入命令:[root@localhost ~]# ifconfig eth0 219.246.177 ...
- 句柄C++
C++中的句柄 这个句柄只是从英文handle翻译过来的,只问句是什么意思难以解释,这个是我从别人的空间收集的信息, 功能上的理解: 什么是"句柄"(handle),handle的 ...