Scala的类和对象
1.类和对象
1.1 相关概念
面向对象:一种编程思想,是基于面向过程的,强调的是以对象为基础完成各种操作
类:属性和行为的集合,是一个抽象的概念
属性/成员变量:名词,用来描述事物的外在特征
行为/成员方法:动词,表示事物能够做什么
对象:类的具体实现
面向对象的三大特征:封装,继承,多态
1.2 创建类和对象
用class来创建类,用new来创建对象
在IDEA中创建项目,并创建一个object类(main方法必须放在Object中):
实际开发中,实体类和测试类会分开写:
后续为了方便,会合并到一起:
1.3 简写方式
用法:
- 如果类是空的,没有任何成员,可以省略
{}
- 如果构造器的参数为空,可以省略
()
示例:
object ClassDemo {
//1.创建Person类
class Person
//2.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//3.创建Person类型的对象
val p = new Person
//4.将对象打印到控制台上
println(p)
}
}
2.定义和访问成员变量
用法:
- 在类中使用
var/val
来定义成员变量 - 对象可以通过
对象名.
的方式来访问成员变量
示例:
object ClassDemo {
//1.创建Person类
class Person{
//2.定义名字和年龄字段
//方式一:普通写法
//val name:String = ""
//方式二:采用类型推断实现
val name = ""
val age = 0
}
//3.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//4.创建Person类型的对象
val p = new Person
//5.给对象的成员变量赋值
p.name = "mike"
p.age = 23
//6.打印属性值
println(p.name, p.age)
}
}
//(mike, 23)
3. 使用下划线初始化成员变量
Scala有一个更简洁的初始化成员变量的方式。
用法:
- 在定义
var
类型的成员变量时,可以使用_来初始化成员变量- String => null
- Int => 0
- Boolean => false
- Double => 0.0
- …
val
类型的成员变量,则需要自己手动初始化
示例:
object ClassDemo {
//1.创建Person类
class Person{
//2.定义名字和年龄字段
//方式一:普通写法
//val name:String = ""
//方式二:采用类型推断实现
//val name = ""
//方式三:采用下划线来初始化成员变量值
//val name:String = _ //报错,因为这种下划线方式只针对var类型的变量
var name:String = _
var age:Int = _
}
//3.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//4.创建Person类型的对象
val p = new Person
//5.给对象的成员变量赋值
p.name = "mike"
p.age = 23
//6.打印属性值
println(p.name, p.age)
}
}
//(mike, 23)
4. 定义和访问成员方法
Scala类中,也是使用def
来定义成员方法的。
示例:
object ClassDemo {
//1.创建Customer类
class Customer{
//2.定义成员变量(姓名和性别)
var name:String = _
var sex = ""
//定义成员方法printHello()
/*def printHello(msg:String) = {
println(msg)
}*/
//简化版
def printHello(msg:String) : Unit = println(msg)
}
//3.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//4.创建Customer类型的对象
val c = new Customer
//5.给对象的成员变量赋值
c.name = "mike"
c.sex = "male"
//6.打印属性值
println(c.name, c.age)
//7.调用成员方法
c.printHello("hi")
}
}
//(mike, male)
//hi
5. 访问修饰符
和Java一样,Scala也可以通过访问修饰符,来控制成员变量和成员方法是否可以被外界访问。
定义:
- 可以在成员前面添加
private
/protected
关键字来控制成员的可见性 - 在Scala中,没有public关键字,任何没有被标为private或protected的成员都是公共的(因此,Scala的权限修饰符只有四种:private, private[this], protected, 默认)
示例:
object ClassDemo {
//1.创建Person类
class Person{
//2.定义私有的成员变量
private var name:String = _
private var age = 0
//3.定义成员方法
def getName():String = name
def setName(name:String):Unit = this.name = name
def getAge():Int = age
def setAge(age:Int):Unit = this.age = age
private def sayHello():Unit = println("hi")
}
//4.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//5.创建Person类型的对象
val p = new Person
//6.给对象的成员变量赋值
//p.name = "mike" //报错,因为被private修饰的内容只能在本类中被直接访问
p.setName("mike")
p.setAge(23)
//7.打印成员变量值
println(p.getName(), p.getAge())
//8.尝试调用Person类中的私有成员方法
//p.sayHello() //报错,因为被private修饰的内容只能在本类中被直接访问
}
}
//(mike, 23)
6. 类的构造器
6.1 主构造器
语法:
class 类名(var/val 参数名:类型 = 默认值,var/val 参数名:类型 = 默认值) {
//构造代码块
}
注意:
- 主构造器的参数列表直接定义在类名后面,添加了val/var表示直接通过主构造器定义成员变量
- 构造器参数列表可以指定默认值
- 创建实例,调用构造器可以指定字段进行初始化
- 整个class中除了字段定义和方法定义的代码都是构造代码
示例:
object ClassDemo {
//1.创建Person类,在主构造器中指定:姓名、年龄
class Person(val name: String = "mike", val age: Int = 23){
//2.在主构造器中输出“调用主构造器”
println("调用主构造器了!')
}
//3.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//4.创建空对象,并打印属性值
val p1 = new Person()
println(s"p1: ${p1.name}, ${p1.age}")
//5.创建全参对象,并打印属性
val p2 = new Person("lee", 24)
println(s"p2: ${p2.name}, ${p2.age}")
//6.创建对象,仅指定年龄,并打印属性值
val p3 = new Person(age = 30)
println(s"p3: ${p3.name}, ${p3.age}")
}
}
//调用主构造器了!
//(mike, 23)
//调用主构造器了!
//(lee, 24)
//调用主构造器了!
//(mike, 30)
6.2 辅助构造器
辅助构造器的目的是让我们有多些创建对象的形式。
语法:
- 定义辅助构造器与定义方法一样,也使用
def
关键字 - 辅助构造器的默认名字都是
this
,且不能修改
def this(参数名:类型,参数名:类型) {
//第一行需要调用主构造器或者其他构造器
//构造器代码
}
示例:
object ClassDemo {
//1.创建Customer类,在主构造器中指定:姓名、地址
class Customer(val name: String, val address: String) {
//2.定义辅助构造器,接收一个数组类型的参数
def this(arr:Array[String]) {
//细节:辅助构造器第一行代码必须访问主构造器或其他的辅助构造器
this(arr(0), arr(1))
}
}
//3.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//4.通过辅助构造器创建Customer类型的对象
val c = new Customer(Array("mike", "beijing"))
//val c2 = new Customer("lee", "shanghai") //通过主构造器创建对象
//5.打印属性值
println(c.name, c.address)
}
}
//(mike, beijing)
7. 单例对象
Scala中是没有static关键字的,要想定义类似于Java中的static变量、static方法,就要用到Scala中的单例对象,即object。
7.1 定义单例对象
单例对象表示全局仅有一个对象,也叫孤立对象。定义单例对象和定义类很像,就是把class换成object。
格式:
object 单例对象名{ }
注意:
- 在object中定义的成员变量类似于Java中的静态变量,在内存中都只有一个对象
- 在单例对象中,可以直接使用
单例对象名.
的形式调用成员
示例:
object ClassDemo {
//1.定义单例对象Dog
object Dog {
//2.定义一个变量,用来保存狗腿的数量
val leg_num = 4
}
//3.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//4.直接打印狗腿数量
println(Dog.leg_num)
}
}
//4
7.2 在单例对象中定义方法
在单例对象中定义的成员方法类似于Java中的静态方法。
示例:
object ClassDemo {
//1.定义单例对象PrintUtil
object PrintUtil {
//2.定义一个方法,用来打印分割线
def printSpliter() = println("-" * 15)
}
//3.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//4.调用单例对象中的成员方法,打印分割线
PrintUtil.printSpliter()
}
}
//---------------
8. main方法
Scala程序中,如果要运行一个程序,必须有一个main方法。在Java中main方法是静态的,而在Scala中没有静态方法。所以,Scala中这个main方法必须放在一个单例对象中。
8.1 定义main方法
def main(args:Array[String]):Unit = {
//方法体
}
示例:
def main(args:Array[String]):Unit = {
println("hi")
}
//hi
8.2 继承App特质
创建一个object,继承App特质(Trait),然后将需要编写在main方法中的代码,写在object的构造方法体内。
object 单例对象名 extends App {
//方法体
}
示例:
object ClassDemo extends App {
println("hi")
}
//hi
9.伴生对象
在 Java 中有一些类,会同时有静态内容和非静态内容,在 Scala 中想要实现类似效果可以使用伴生对象来实现。
9.1 定义伴生对象
一个 class 和 object 具有相同的名字,这个 object 被称为伴生对象,这个 class 被称为半生类。
伴生对象和半生类可以互相访问 private 属性,必须写在同一个scala源文件。
示例:
object ClassDemo {
//1.定义伴生类Generals
class Generals { //里面写的内容都是非静态的
//2.定义toWar()方法,表示打仗
def toWar() = println(s"武将拿着${Generals.armsName}武器,上阵杀敌")
}
//3.定义伴生对象
object Generals { //里面写的内容都是静态的
//4.定义一个私有的成员变量,用来保存武器的名称
private val armsName = "大刀"
}
//5.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//6.创建伴生类的对象
val c = new Generals
//7.调用toWar()方法
c.toWar()
}
}
//武将拿着大刀武器,上阵杀敌
9.2 private[this]访问权限
如果某个成员变量权限为 private[this],表示只能在当前类访问,伴生对象也不能直接访问。
示例:
object ClassDemo {
//1.定义伴生类Person,并在其中定义一个name字段
//class Person(private[this] var name:String) { //这样写会报错
class Person(private var name:String) { //里面写的内容都是非静态的
}
//2.定义Person类的伴生对象
object Person { //里面写的内容都是静态的
//3.定义一个printPerson()方法,用来打印某个Person对象的属性值
def printPerson(p:Person) = println(p.name)
}
//4.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//5.调用伴生对象中的printPerson()方法,尝试是否可以访问private[this]修饰的内容
val p = new Person("mike")
Person.printPerson(p)
}
}
//mike
9.3 apply方法
Scala中,支持创建对象的时候不用new这个关键字(免new
),实现需要通过对伴生对象的apply方法来实现。
定义apply方法的格式:
object 伴生对象名 {
def apply(参数名:参数类型, (参数名:参数类型...) = new 类(...)
}
创建对象:
val 对象名 = 伴生对象名(参数1,参数2,...)
示例:
object ClassDemo {
//1.定义伴生类Person, 属性:姓名、年龄
class Person(var name:String = "", var age:Int = 0) {}
//2.定义Person类的伴生对象
object Person {
//3.定义一个apply()方法,用来实现创建Perosn对象时候免new
//apply()方法,Scala SDK会自动调用
def apply(name:String, age:Int) = new Person(name, age)
}
//4.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//5.创建Person类型的对象
val p = Person("mike", 23)
//6.打印对象的属性值
println(p.name, p.age)
}
}
//(mike, 23)
10. 案例:定义工具类
Scala中工具类的概念和Java中是一样的,都是
- 构造方法全部私有化,目的是不让外界通过构造方法来创建工具类的对象
- 成员全部是静态化,意味着外界可以通过"类名."的形式来访问工具类中的内容
综上所述,Scala中只有object单例对象
满足上述要求
示例:
import java.text.SimpleDateFormat
import java.util.Date
object ClassDemo {
//1.定义工具类DataUtils
object DataUtils {
//2.细节:定义一个SimpleDateFormat类型的对象
var sdf:SimpleDateFormat = null
//3.定义data2String()方法,用来将日期对象转换成其对应的字符串
def data2String(date: Date, template:String) = {
sdf = new SimpleDateFormat(template)
sdf.format(date)
}
//4.定义string2Date()方法,用来将字符串形式的日期转换成其对应的字符串
def string2Date(dateString: String, template:String) = {
sdf = new SimpleDateFormat(template)
sdf.parse(dateString)
}
//5.定义main函数,它是程序的主入口
def main(args: Array[String]): Unit = {
//6.测试date2String()方法
println(DateUtils.date2String(new Date(), "HH:mm:ss"))
//7.测试string2Date()方法
println(DateUtils.string2Date("1234年5月21日", "yyyy年MM月dd日"))
}
}
//20:12:46
//Tue May 21 00:00:00 CST 1314