快学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 ...
随机推荐
- deb
1.APT方式 (1)普通安装:apt-get install softname1 softname2 …; (2)修复安装:apt-get -f install softname1 softname ...
- Linux中如何设置java环境变量
这里介绍Linux下如何设置java环境变量. 工具/原料 Linux java环境变量 方法/步骤 1 查看java的安装路径 查看java执行路径 配置java环境变量 java的安装 ...
- Arch最小化安装LXDE桌面环境
安装最小化的LXDE桌面环境: pacman -S lxde-common 安装LXDE Session: pacman -S lxsession 不安装这个没法登录进桌面环境 安装LXDE面板: p ...
- css3部分属性兼容性别扭写法(因为很多我就叫他别扭了,希望全面早早支持css3吧)
/*圆角class,需要设置圆角的元素加上class名称*/ .roundedCorners{ -webkit-border-radius: 10px;/*webkit内核浏览器*/ -moz-bor ...
- Swift-HELP
//获取网页地址对应的字符串 var urlString = url.absoluteURL.absoluteString
- go语言实现寻找最大子数组
题目:给定一个数字序列,寻找其中各元素相加和最大的子数组 /* 寻找最大子数组go语言实现 */ package main import fmt "fmt" func main() ...
- ACM心路
又到了夏天了,这个季节最容易发春,最近上课效率怎么这么低,哎,,别发春了,好好学习,天天向上,现在想妹子,都是空想,没有什么实际意义,纯属浪费时间,浪费生命,不如节约点时间到学习上,不学无术,到嘴边的 ...
- Struts2如何传值到jsp页面
Struts2如何传值到jsp页面 不是action传值到jsp页面,而是jsp页面获取action中的属性值,或者范围(如request,session,application等)里的值.所以,有两 ...
- Linux Shell 小脚本经典收藏
原文:http://www.cnblogs.com/Javame/p/3867686.html 1.在两个文件中找出相同的号码 diff -y xx.txt oo.txt | egrep -v &qu ...
- 在Java 线程中返回值的用法
http://icgemu.iteye.com/blog/467848 在Java 线程中返回值的用法 博客分类: Java Javathread 有时在执行线程中需要在线程中返回一个值:常规中我们 ...