scala学习手记12 - 字段、方法和构造函数
在上一节创建了一个scala类,如果没有更多的方法,scala类的定义还可以更简单一些,看一下下面这个CreditCard类的定义:
class CreditCard(val number: Int, var creditLimit: Int)
是的,只用一行就完成了类的定义,连大括号都不需要。
因为scala也是运行在JVM上,可以考虑以java的方式来看看编译后的类文件。查看的方式还是比较灵活的,可以使用JD-GUI,也可以使用javap –private CreditCard命令,还有一个在线反编译的网站ShowMyCode。反编译后的Java代码:
public class CreditCard { public int number() {
return number;
} public int creditLimit() {
return creditLimit;
} public void creditLimit_$eq(int x$1) {
creditLimit = x$1;
} public CreditCard (int number, int creditLimit) {
this.number = number;
this.creditLimit = creditLimit;
super ();
} private final int number;
private int creditLimit;
}
好长的java代码。首先scala默认将CreditCard类转换为了public。因为在CreditCard.scala中将number声明为val,所以在反编译生成的java代码中,number被定义为final。此外在编译后的代码中还可以看到一个构造器以及读写成员变量的方法。可以看到成员变量的getter和setter与我们在java中习惯使用的命名方式有些不一致。此外由于number有final修饰符,因此就没有它的setter方法。如果scala中的成员变量的定义符号既不是var也不是val,那Scala就会为之创建一个private字段以及private getter和setter方法,也因此不能在类外部访问这个成员变量了。
放到类定义中的所有可执行语句或表达式都会被视为类的构造器的组成部分。下面的代码就是一个示例:
class Sample {
println("You are constructing an instance of Sample")
} new Sample
在这段代码中先定义了一个类Sample,随后又创建了一个Sample类的实例,执行看一下:
在创建实例的时候输出了类定义中的print语句,因为这段print语句是构造器的一部分。
除了在主构造函数中提供成员变量,我们还可以在类里面定义其他字段、方法、零个或多个副构造函数。在下面这个类中在类里面定义了一个成员变量position、一个副构造函数this()、并且重写了toString()方法。
class Person(val firstName: String, val lastName: String) { private var position: String = _ println("Creating " + toString()) def this(firstName: String, lastName: String, positionHeld: String) {
this(firstName, lastName)
position = positionHeld
} override def toString(): String = {
firstName + "" + lastName + " holds " + position + " position "
}
} val john = new Person("John", "Smith", "Analyst")
println(john)
val bill = new Person("Bill", "Walker")
println(bill)
执行代码的结果如下:
稍稍关注下副构造函数的实现:如果有主构造函数的话,那么副构造函数的第一行必须是主构造函数或者其它副构造函数的调用。这一点倒是和java继承父类时有点相似。
此外还值得注意的就是成员变量position的定义,把这一行单独拎出来看看吧:
private var position: String = _
首先比较有趣的是初始化赋值,赋值是一个“_”——下划线。在这里“_”代表相应类型的默认值。对于Int,它的值是0;对于Double,它的值是0.0;对于String,它的值就是null。通过使用“_”,可以很方便地为var成员变量设置初始默认值。不过不能为val成员使用“_”,因为val成员不允许修改,所以必须显式指定初始值
通过查看Person.scala的字节码反编译出来的java类,可以看到scalac编译器为成员变量position默认设置了getter和setter方法(虽然没有按照我们习惯的JavaBean的方式进行设置)。scala中定义的成员变量的可见性在反编译出来的Java代码中由getter和setter方法的访问权限来控制。
如果更喜欢传统的JavaBean式的注解,可以在成员变量定义时添加注解@BeanProperty:
@BeanProperty var position: String = _
声明前记得导入注解。不过这也有一点限制:此时成员变量不可再声明为private。而且这样做只是会再额外生成两个JavaBean式的getter和setter,原来的getter和setter也会继续保留。这可以在编译Person类以后再用javap –private验证一下:
就是这样。
#######
scala学习手记12 - 字段、方法和构造函数的更多相关文章
- scala学习手记34 - trait方法的延迟绑定
trait的方法的延迟绑定就是先混入的trait的方法会后调用.这一点从上一节的实例中也可以看出来. 下面再来看一个类似的例子: abstract class Writer { def write(m ...
- scala学习手记20 - 方法返回类型推断
除了推演变量的类型,scala也会推演方法的返回类型.不过这里有一处需要注意:方法返回类型的推演依赖于方法的定义方式.如果用等号"="定义方法,scala就会推演方法返回类型:否则 ...
- scala学习手记16 – scala中的static
前面两节学了scala的对象和伴生对象,这两个在使用的时候很有些java的静态成员的意思. scala中没有静态字段和静态方法.静态成员会破坏scala所支持的完整的面向对象模型.不过可以通过伴生对象 ...
- scala学习手记13 - 类继承
在scala里,类继承有两点限制: 重写方法需要使用override关键字: 只有主构造函数才能往父类构造函数中传参数. 在java1.5中引入了override注解,但不强制使用.不过在scala中 ...
- scala学习手记2 - scala中的循环
先来看一段Java中的循环: for (int i = 1; i < 4; i++) { System.out.print(i + ","); } 毫无疑问,scala可以让 ...
- scala学习手记38 - 方法命名约定和for表达式
方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. ...
- scala学习手记10 - 访问修饰符
scala的访问修饰符有如下几个特性: 如果不指定访问修饰符,scala默认为public: 较之Java,scala对protected的定义更加严格: scala可以对可见性进行细粒度的控制. s ...
- scala学习手记28 - Execute Around模式
我们访问资源需要关注对资源的锁定.对资源的申请和释放,还有考虑可能遇到的各种异常.这些事项本身与代码的逻辑操作无关,但我们不能遗漏.也就是说进入方法时获取资源,退出方法时释放资源.这种处理就进入了Ex ...
- scala学习手记23 - 函数值
scala的一个最主要的特性就是支持函数编程.函数是函数编程中的一等公民:函数可以作为参数传递给其他函数,可以作为其他函数的返回值,甚至可以在其它函数中嵌套.这些高阶函数称为函数值. 举一个简单的例子 ...
随机推荐
- 【IDEA】启动项目报错:3 字节的 UTF-8 序列的字节 3 无效
一.报错和原因: 项目起服务出错.具体报错就不贴了,报错主要是"3 字节的 UTF-8 序列的字节 3 无效". 分析:主要就是项目编码问题,IDEA中估计就是配置不对,没必要纠结 ...
- Jmeter--正则表达式提取值
博客首页:http://www.cnblogs.com/fqfanqi/ 设置界面如下: Apply to:应用范围的选择: Field to check:检查的领域,即需要提取内容的地方. 下面是各 ...
- PAT 1013 Battle Over Cities(并查集)
1013. Battle Over Cities (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue It ...
- python装饰器的学习笔记
此博文是我对装饰器的一些理解,如果有错误欢迎及时留言,我会第一时间向大家学习. 一.什么是装饰器 1.从字面意义来看: 是用来给函数装饰打扮的函数 2.理论上可以理解为: (1).不改变函数的运行方式 ...
- USB 3.0:那些你需要知道的事
在过去14年来,通用串行总线(USB)已成为计算机和外部设备之间的标准接口.不管是移动硬盘.相机.鼠标.键盘.打印机,还是扫描仪,它们和计算机之间的数据传输一般均采用USB线.USB接口也的确是“通用 ...
- 一.数据库连接对象connection
1.python 3.5,需要把MySQLdb换成pymysql
- MongoDB-5: 查询(游标操作、游标信息)
一.简介 db.collection.find()可以实现根据条件查询和指定使用投影运算符返回的字段省略此参数返回匹配文档中的所有字段.并返回到匹配文档的游标,可以随意修改查询限制.跳跃.和排序顺序的 ...
- 我的Android进阶之旅------>Android Activity的singleTask加载模式和onActivityResult方法之间的冲突
今天调试一个bug的时候,情景如下: 一个Activity A,需要用startActivityForResult方法开启Activity B.Activity B的launch mode被设置为si ...
- Python3+Selenium3自动化测试-(二)
python3 元素定位和操作方法总结 # coding=utf-8 ''' #8种元素定位方法 find_element_by_id() find_element_by_name() find_el ...
- django的安装、文件解释与基本命令
1.安装 pip install django==1.9.8 2.新建一个django project django-admin startproject mysite #创建工程文件 cd mysi ...