一:类和构造函数
1. 类和构造函数
object A {
def main(args: Array[String]): Unit = {
val xiaoMing = new Boy("xiaoming", 20)
val xiaoGang = new Boy("xiaoGang", 18, "china")
println(xiaoMing)
println(xiaoGang)
}
}
class Boy(name : String, age : Int) {
// 上面紧跟在类名后面的为主构造器
// 属性,不需要get,set方法
// var 修饰默认可以获取和修改,val 修饰只能获取,无法修改
// 下划线表示给个默认值,String默认值是null
var country : String = _
// 辅助构造器用于实现构造器的重载扩展
def this(name : String, age : Int, country : String){
// 第一行必须先调用主构造器
this(name, age)
this.country = country
}
override def toString: String = name + age + country
}
2. 主构造函数的参数修饰符
定义5个类,以及对应的字节码反编译成Java后文件:
/** class A(name : String) */
public class A
{
public A(String name) {}
}
/** class B(val name : String) */
public class B
{
private final String name;
public String name()
{
return this.name;
}
public B(String name) {}
}
/** class C(var name : String) */
public class C
{
private String name;
public C(String name) {}
public void name_$eq(String x$1)
{
this.name = x$1;
}
public String name()
{
return this.name;
}
}
/** class D(private val name : String) */
public class D
{
private final String name;
private String name()
{
return this.name;
}
public D(String name) {}
}
/** class E(private[this] val name : String) */
public class E
{
public E(String name) {}
}
所以,小结如下:
主构造器参数 | 生成的字段 | 生成的方法 |
---|---|---|
name:String | 不生成任何字段 | 不生成任何方法 |
val/var name:String | 私有字段 | 公共的getter/setter、getter方法 |
private val/var name:String | 私有字段 | 私有的getter/setter、getter方法 |
private[this] val/var name:String | 不生成任何字段 | 不生成任何方法 |
二:单例对象和伴生对象
单例(Singleton)对象是一个通过使用object关键字而不是使用class关键字声明的对象,Scala没有java那样的static的概念,因此需要通过单例对象提供程序执行的入口点,或者用于工具类,常量类的存放。上节的object A 就是单例对象。
当单例对象和同一文件中的类名一致时,此单例对象就称同名类的伴生对象。类和其伴生对象可以互相访问各自的私有方法。
class Singleton{
private var calssValue : String = "class"
// 访问伴生对象的私有属性
def m = println(Singleton.objectValue)
}
object Singleton {
private var objectValue : String = "object"
def main(args: Array[String]): Unit = {
var s = new Singleton()
// 访问类的私有属性
println(s.calssValue)
s.m
}
}
三:特质、抽象类和继承
trait(特质)和Java的接口类似。在Scala中,继承父类只能单继承,但是实现trait可以多个。trait可以定义属性和方法的实现,Java1.8开始也可以,之前版本不行。
当实现单个trait时,直接使用extends即可,但是实现多个trait时,第二个开始使用with关键字。
class Human extends Run with Talk {
override def run: Unit = println("can run")
override def talk: Unit = println("can talk")
}
trait Run {
def run
}
trait Talk {
def talk
}
四:apply 和 unapply方法
当一个类的实例后直接跟参数列表时,编译器会调用该实例上的apply方法,一般都是在类的伴生对象中定义apply方法,用于简化类的创建。
同时,unapply方法的目的是提取正在寻找的特定值,当使用match语句比较提取器对象时,将自动执行unapply方法。
object a {
def main(args: Array[String]): Unit = {
val h1 = new Human("xiaoming", 1)
val h2 = new Human("xiaoming", 1)
println(h1 == h2) // false
val h3 = Human
val h4 = Human
println(h3 == h4) // true
val h5 = Human("xiaoming", 1)
val h6 = Human("xiaoming", 1)
println(h5 == h6) // false
val humanList = List(h1, h2, h3, h4, h5, h6, a)
for (h <- humanList) {
h match {
case Human("xiaoming", _) => println("it is xiaoming")
case Human => println("it's human, but I do not know")
case _ => println("not human")
}
}
/*
* it is xiaoming
it is xiaoming
it's human, but I do not know
it's human, but I do not know
it is xiaoming
it is xiaoming
not human
*/
}
}
class Human(){
var name : String = _
var age : Int = _
def this(name : String, age : Int) {
this()
this.name = name
this.age = age
}
}
object Human{
def apply(name: String, age: Int): Human = new Human(name, age)
def unapply(human: Human): Option[(String, Int)] = {
if (human == null)
None
else
Some(human.name, human.age)
}
}