类定义
知识点
每个类都有一个主构造器,这个构造器和类的定义“交织”在一起,它的参数直接成为类的字段,主构造器执行类体中所有的语句
类中的字段自动带getter和setter方法
用@BeanProperty注解生成JavaBean的getXxx/setXxx方法
辅助构造器是可选的,它们都叫做this
类定义
定义及使用
scala> class Counter {
| private var value = 0
| def increment() {value += 1}
| def current() = value
| }
defined class Counter
scala> val myCounter = new Counter
myCounter: Counter = Counter@396a0391
scala> myCounter.increment()
scala> println(myCounter.current)
1
scala> myCounter.increment()
scala> println(myCounter.current)
2
说明:
Scala源文件中可以包含多个类
调用无参数方法或创建无参数对象时,可以写圆括号,也可不写
约定,对于改值器方法(即改变对象状态的方法)用(),而对于取值器方法(不改变对象状态的方法)去掉()
Scala对每个字段都提供getter和setter方法,如下定义一个公有字段
scala> class Person {
| var age = 0
| }
defined class Person
Scala生成面向JVM的类时,其中有一个私有的age字段及相应的两个公有的getter和setter方法;
对于私有字段,getter和setter方法也是私有的;
在Scala中,getter和setter分别叫做age和age_= (注意下划线和等号间没有空格)
重新定义getter和setter方法,如:年龄不能设置成比现在的更小
scala> class Person{
| private var privateAge = 0
| def age = privateAge
| def age_= (newValue: Int) {
| if (newValue > privateAge) privateAge = newValue
| }
| }
defined class Person
// 测试
scala> val fred = new Person
fred: Person = Person@718f1128
scala> fred.age = 30
fred.age: Int = 30
scala> fred.age
res0: Int = 30
scala> fred.age = 21
fred.age: Int = 30
scala> fred.age
res1: Int = 30
如何控制Scala对每个字段生成getter和setter的方法?
如果字段是私有的,则getter和setter方法也是私有的
如果字段是val, 则只生成getter方法
如果不需要任何getter和setter,将字段声明为private[this]即可
用@BeanProperty注解生成JavaBean的getXxx/setXxx方法
scala> import scala.reflect.BeanProperty
import scala.reflect.BeanProperty
scala> class Person{
| @BeanProperty var name: String = _
| }
defined class Person
将会生成四个方法:
name: String
name_=(new Value: String): Unit
getName(): String
setName(newValue: String): Unit
如果以主构造器参数的方式定义字段,并且需要JavaBeans版本的getter和setter方法,可以在构造器参数上加注解即可
class Person (@BeanProperty val name: String)
构造器
主构造器
在Scala中,每个类都有主构造器。与类定义交织在一起。
如果类名之后没有参数,则该类具备一个无参数主构造器。
如果有参数,则把参数直接放置在类名之后。主构造器的参数被编译成字段,其值被初始化成构造时传入的参数。
主构造器会执行类定义中的所有语句。
class Person(val name: String, val age: Int) {
// 在定义对象时,println语句是主构造器的一部分,会被执行
println("Just constructed person")
def desc = name + " is " + age + " years old."
}
可以通过在主构造器中使用默认参数来避免过多地使用辅助构造器。
如果想让主构造器成为私有的,可以在参数列表前放置private关键字。
// Scala
class Person(val name: String, val age: Int) {
}
// 以上代码相当于Java的以下代码
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// getter and setter
...
}
辅助构造器
除了主构造器外,可以定义任意多的辅助构造器
辅助构造器的名称为this。
每一个辅助构造器都必须以一个对先前已经定义的其他辅助构造器或主构造器的调用开始。
class Person {
private var name = ""
private var age = 0
def this(name: String) {
// 调用主构造器
this()
this.name = name
}
def this(name: String, age: Int) {
// 调用前一个辅助构造器
this(name)
this.age = age
}
}
// 可以以三种方式构造对象:
// 主构造器
val p1 = new Person
// 第一个辅助构造器
val p2 = new Person("Fred")
// 第二个辅助构造器
val p3 = new Person("Fred", 42)
单利对象及伴生对象
知识点
用对象作为单例或存放工具方法,Scala没有静态方法或字段
类可以有一个同名的伴生对象
对象的apply方法通常用来构造伴生类的新实例
Scala的main函数定义
单例对象
Scala没有静态方法或字段,可以用object语法定义结构,对象定义了类的单个实例。
对象的构造器在该对象第一次使用时被调用。
不能提供构造器参数。
作为存放工具函数或常量的地方。
高效地共享单个不可变实例。
scala> object Accounts {
| private var lastNumber = 0
|
| def newUniqueNumber() = {
| lastNumber += 1
| lastNumber
| }
|
| }
defined module Accounts
scala>
scala> Accounts.newUniqueNumber()
res2: Int = 1
scala> Accounts.newUniqueNumber()
res3: Int = 2
伴生对象
在Scala中,可通过类和类同名的“伴生”对象来达到静态方法的目的。
类和它的伴生对象可以相互访问私有特性,它们必须存在于同一个源文件中
apply方法
一般在伴生对象中定义apply方法
常用于初始化操作或创建单例对象
在生成这个类的对象时,就省去了new关键字
在遇到Object(参数1,参数2,......,参数n)时就会自动调用apply()方法
main函数
Scala程序必须从一个对象的main方法开始
有两种方法定义
// 执行println语句
object Main {
def main(args: Array[String]): Unit = {
println("=" * 10)
}
}
// 扩展App特质
object Main extends App {
println("=" * 10)
}
完事示例
class Account {
val id = Account.newUniqueNumber()
private var balance = 0.0
def deposit(amount: Double): Double = {
balance += amount
balance
}
def nowBalance = balance;
}
object Account {
private var lastNumber = 0
private def newUniqueNumber() = {
lastNumber += 1
lastNumber
}
}
object Main {
def main(args: Array[String]): Unit = {
val account = new Account
println(account.id)
println(account.deposit(1))
println("=" * 10)
val account1 = new Account
println(account1.id)
println(account1.deposit(10))
println("=" * 10)
println("a " + account.nowBalance + "; b " + account1.nowBalance)
}
}
// ======= 执行结果
1
1.0
==========
2
10.0
==========
a 1.0; b 10.0
// =================使用apply示例===================
package com.gemantic.bigdata
/**
* @author Yezhiwei
* @date 18/1/4
*/
class Student private (val sno: Int, val name: String){
override def toString: String = {
"sno " + sno + " name " + name
}
}
object Student {
private var sno = 0
private def newSno = {
sno += 1
sno
}
def apply(name: String): Student = {
println("call apply method...")
new Student(newSno, name)
}
}
object StudentMain extends App {
// no new
val student1 = Student("Yezhiwei")
println(student1.toString)
println("*" * 10)
val student2 = Student("Yezhiwei")
println(student2.toString)
}
// 运行结果
call apply method...
sno 1 name Yezhiwei
**********
call apply method...
sno 2 name Yezhiwei