Scala的面向对象:类似Java
把数据属性及数据操作的方法放在一起,作为一个依存的整体,就是对象。
一、面向对象的基本概念
1、封装:类class
2、继承
3、多态
二、类的定义
关键字class。
2.1 简单类和无参数方法。
class Counter{
private var value=0;
def increment(){}
def current()=value;
}
2.2 创建类
//注意:class前面没有public修饰
- 举例:创建一个学生类
//代表一个学生的信息
class Student1 {
//定义学生的属性
private var stuID:Int = 0
private var stuName:String = "Tom"
private var age:Int = 20
//定义成员方法(函数):get 和set
//定义名字和年龄的get和set
def getStuName():String = stuName
def setStuName(newName:String) = this.stuName = newName
def getStuAge():Int = age
def setStuAge(newAge:Int) = this.age = newAge
}
//如果要开发main方法,需要在main方法中定义该类的伴生对象
//测试Student1类,创建main函数(写到Object中)
//注意:object和class的名字可以不一样,如果一样了,这个object就叫做该class的伴生对象
object Student1{
def main(args: Array[String]): Unit = {
//创建学生对象
var s1 = new Student1
//第一次访问属性并输出
println(s1.getStuName()+"\t"+s1.getStuAge())
//访问set方法
s1.setStuName("Mary")
s1.setStuAge(22)
println(s1.getStuName()+"\t"+s1.getStuAge())
//再输出一次:直接访问私有的属性
println("*************直接访问私有的属性************")
println(s1.stuID +"\t"+ s1.stuName+"\t"+s1.age)
//注意:可以直接访问类的私有成员 为什么可以? ----> 属性的get和set方法
}
}
2.3 getter和setter方法
当定义属性是private时候,scala会自动为其生成对应的get和set方法。
private var stuName:String = "Tom"
- get方法: stuName ----> s2.stuName() 由于stuName是方法的名字,所以可以加上一个括号
- set方法: stuName_= ----> stuName_= 是方法的名字
定义属性:private var money:Int = 1000 希望money只有get方法,没有set方法??
办法:将其定义为常量private val money:Int = 1000。
- private[this]的用法:
该属性只属于该对象私有,就不会生成对应的set和get方法。如果这样,就不能直接调用,例如:s1.stuName —> 错误。
在Scala中,方法也可以访问该类的所有对象的私有字段,成为类私有字段;
但在Scala中,允许定义更加严格的字段访问控制,通过private[this]来实现,称为对象私有字段,即只能在对象内部访问的字段,
private[this] val money:Int = 1000
def test(other:Person)=this.money.equal(other.money)
方法内不能访问其他对象的对象私有字段(salary)。
三、内部类
内部类(嵌套类):就是在一个类的内部,定义了另外一个类。
object Student2{
def main(args: Array[String]): Unit = {
var s2 = new Student2
s2.addNewCource("chinese",1)
s2.addNewCource("math",2)
s2.addNewCource("english",3)
//输出
println(s2.stuName,s2.stuAge)
//遍历选的课
for (s <- s2.courseList) println(s.courseName+":"+s.creditId)
}
}
class Student2 {
//定义一个内部类,记录学生选课信息
//这里定义了该类的主构造器
class Course(val courseName:String,val creditId:Int){
}
private var stuName:String="Tom"
//抽象属性可以不被初始化
// var stuAge:Int =0
private var stuAge:Int=18
//定义一个ArrayBuffer记录学生选修的所以课程
private var courseList = new ArrayBuffer[Course]()
def addNewCource(cname:String,creditId:Int): Unit ={
//创建新课程
var c=new Course(cname,creditId)
//将课程加入list
courseList+=c
}
四、类的构造器:两种
1、主构造器:和类的声明在一起,并且一个类只有一个主构造器。
2、辅助构造器:一个类可以有多个辅助构造器,通过关键字this。
相当于java中构造器调用其它构造器。
object Student3 {
def main(args: Array[String]): Unit = {
val s3=new Student3("123")
print(s3.stuName+":"+s3.stuAge)
}
}
//主构造器和类的声明在一起
//只能有一个主构造器
class Student3(var stuName:String,var stuAge:Int) {
//两种写法
def this(stuName: String) = this(stuName, 20)
//辅助构造器
def this(stuAge: Int) {
//主构造器
this("123", 20)
}
}
类的构造器分为:主构造器、辅助构造器
五、Object对象:相当于Java中的static。
Scala没有静态的修饰符,但Object对象下的成员都是静态的 ,若有同名的class,将其作为它的伴生类。
在Object中一般可以为伴生类做一些初始化等操作。
1、Object中的内容都是静态的
2、Scala中,没有静态修饰符static
3、如果class的名字,跟object的名字一样,这时候就把这个object叫做类的伴生对象。
4、举例
(1)使用object实现单例模式:一个类只有一个对象。
如果在Java中,构造器定义为private,提供getInstance方法
(2)使用App对象:应用程序对象。
好处:可以省略main方法
/**
* scala中的object相当于静态代码块
* 利用object对象实现单例
*/
object CreditCard {
//变量保存信用卡号【this】,即该属性只属于该对象
private[this] var creditCardNumber:Int=0
//注意:当是基本数据类型的时候需要进行返回。是Unit的时候不需要返回。
//这个方法由于定义在object中,所以是静态的
def generateNewCCNumber():Long={
creditCardNumber +=1
creditCardNumber
}
def main(args: Array[String]): Unit = {
println(generateNewCCNumber())
println(generateNewCCNumber())
println(generateNewCCNumber())
print(creditCardNumber)
}
六、apply方法
遇到如下形式的表达式时,apply方法就会被调用:
Object(参数1,参数2,…,参数N)。
通常,这样一个apply方法返回的是伴生类的对象;
其作用是为了省略new关键字,
可以省略new关键字,根据自己的需要进行初始化。
apply方法必须写在伴生对象中。
//创建一个数组
scala> var myarray = Array(1,2,3) ----> 使用了apply方法
//myarray: Array[Int] = Array(1, 2, 3)
scala> //本质就是创建一个Array对象
scala> //省略了new关键字
object Student4{
//定义自己的apply方法
// 如果没有这个的apply方法,下面省略new的语句就会报错
def apply(stuName:String)={
new Student4(stuName)
}
def main(args: Array[String]): Unit = {
var s5=new Student4("hello")
println(s5.stuName)
//由于省略关键字,创建这个对象的时候,就会在
// object 找对应的apply方法
var s=Student4("world")
println(s.stuName)
}
}
class Student4(val stuName:String) {
}
七、继承
1、跟Java一样,使用关键字extends
2、抽象类、抽象字段
例一:Person1类继承P1类
class P1(val name:String,val age:Int){
def sayHello()="hello"
}
//override去覆盖父类的属性
class Person1( override val name:String,override val age: Int,val sex:String) extends P1 (name,age){
}
object p{
def main(args: Array[String]): Unit = {
var aa =new P1("hong",11)
println(aa.name+":"+aa.age)
var bb=new Person1("lan",21,"f")
println(bb.sex)
var cc=bb.sayHello()
println(cc)
}
}
例二:在子类中重写父类的方法
class Person1( override val name:String,override val age: Int,val sex:String) extends P1 (name,age){
//override去覆盖父类的方法,必须加
override def sayHello()="world"
}
例三:使用匿名子类
//使用匿名子类去创建一个P1的对象,并重写P1的方法
var t:P1=new P1("Jack",26){
override def sayHello()="I am Jack"
}
println(t.sayHello())
例四:使用抽象类(abstract)。抽象类中包含抽象方法,抽象类只能用来继承。
//有未实现的方法,所以为abstract修饰
abstract class Vehicle {
def checkType():String
def showName()
}
class Car extends Vehicle{
override def checkType(): String = "123"
override def showName(): Unit = {
println("unknown")
}
}
object Tets{
def main(args: Array[String]): Unit = {
var v1 = new Vehicle {
override def checkType(): String = "bus"
override def showName(): Unit = {
println("byd")
}
}
v1.showName()
var v2 =new Car
v2.showName()
}
}
例五:使用抽象字段。抽象字段就是一个没有初始值的字段。
abstract class Vehicle {
def checkType():String
def showName()
var id:Int
}
当去继承Vehicle的时候需要对抽象字段赋值。
抽象字段就是一个没有初始化的字段。
八、特质(trait)
类似Java中的抽象类,并且支持多重继承。
本质:就是抽象类,特点:支持多重继承。
trait就是抽象类。trait跟抽象类最大的区别:trait支持多重继承。
extends…with
trait Human {
var id:Int
var name:String
def show():String
}
trait Action {
def run():String
def eat():String
}
trait Action1 {
def fly():String
}
//多个Trait,用extends...with...with...
//提供主构造器
class Fireman( var id:Int, var name:String,val action:String) extends Human with Action with Action1 {
override def show(): String = id+":"+name+":"+action
override def run(): String = "run fast"
override def eat(): String = "eat less"
override def fly(): String = "cat not fly"
}
object Excute{
def main(args: Array[String]): Unit = {
var fireman=new Fireman(10,"xiaohua","run")
println(fireman.show())
}
}
九、包和包对象
9.1 包
Scala的包和Java中的包或者C++中的命名空间的目的是相同的:管理大型程序中的名称。
Scala中包的定义和使用:
- 包的定义
- 包的引入:Scala中依然使用import作为引用包的关键字
- 而且Scala中的import可以写在任意地方(Java中,import写在最前面)
9.2 包对象
包可以包含类、对象和特质,但不能包含函数或者变量的定义。很不幸,这是Java虚拟机的局限。
把工具函数或者常量添加到包而不是某个Utils对象,这是更加合理的做法。
Scala中,包对象的出现正是为了解决这个局限。
Scala中的包对象:常量,变量,方法,类,对象,trait(特质),包。