目录
-
类和对象
scala是支持面向对象的,也有类和对象的概念。我们依然可以基于scala语言来开发面向对象的应用程序。
-
创建类和对象
使用class来定义一个类 new来创建对象
例:
object demo01 {
//创建类
class user{}
def main(args: Array[String]): Unit = {
//创建对象
var u = new user()
println("hello word")
}
}
-
定义和访问成员变量
一个类会有自己的属性,例如:人这样一个类,有自己的姓名和年龄。在类中定义、和访问成员变量
例:
object demo01 {
//创建类
class user{
// 定义成员变量
val id = "123"
var name = ""
var age = 0
}
def main(args: Array[String]): Unit = {
//创建对象
var u = new user()
u.name = "zhangsan"
u.age = 20
//获取变量值
println(u.id)
println(u.name)
println(u.age)
}
}
-
使用下划线初始化成员变量
1.在定义var类型的成员变量时,可以使用_来初始化成员变量
2.使用下划线初始化,成员变量必须为var(变量),并且要指定数据类型
例:
object demo01 {
//创建类
class user{
// 定义成员变量 使用下划线进行初始化
var id:String = _
var name:String = _
var age:Int = _
}
def main(args: Array[String]): Unit = {
//创建对象
var u = new user()
u.name = "zhangsan"
u.age = 20
//获取变量值
println(u.id)
println(u.name)
println(u.age)
}
}
-
定义成员方法
类可以有自己的行为,scala中也可以通过定义成员方法来定义类的行为。使用def来定义成员方法
例:
object demo01 {
//创建类
class user{
// 定义成员变量 使用下划线进行初始化
var id:String = _
var name:String = _
var age:Int = _
//定义成员方法
def prints (msg:String): Unit = {
println(msg + " hello")
}
}
def main(args: Array[String]): Unit = {
//创建对象
var u = new user()
u.name = "zhangsan"
u.age = 20
//输出成员方法
u.prints("zhangsan")
}
}
-
访问修饰符
1.和Java一样,scala也可以通过访问修饰符,来控制成员变量和成员方法是否可以被访问。
2.可以在成员前面添加private/protected(私有的/受保护的)关键字来控制成员的可见性。
3.scala中,没有public关键字,任何没有被标为private或protected的成员都是公共的
例:
object demo02 {
class Persion {
//定义成变量
private var name: String = ""
private var age: Int = 0
//定义成员方法
def getName() = {
this.name
}
def setName(name: String): Unit = {
this.name = name
}
def getAge() = {
this.age
}
def setAge(age: Int): Unit = {
this.age = age
}
private def getNameAndAge() = {
this.getName() + " " + this.getAge()
}
}
def main(args: Array[String]): Unit = {
//实例化对象
var persion = new Persion();
//调用方法
persion.setName("zhangsan")
persion.setAge(200)
println(persion.getName())
println(persion.getAge())
}
}
-
类的构造器
1.当创建类对象的时候,会自动调用类的构造器。之前使用的都是默认构造器
2.Scala的构造器分为主构造器与辅助构造器
3.主构造器:直接在class括号内添加属性
4.辅助构造器:除了主构造器之外的都是辅助构造器
主构造器
1.主构造器的参数列表是直接定义在类名后面,添加了val/var表示直接通过主构造器定义成员变量
2.构造器参数列表可以指定默认值
3.创建实例,调用构造器可以指定字段进行初始化
4.整个class中除了字段定义和方法定义的代码都是构造代码
格式:
class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值){
// 构造代码块
}
例:
object demo03 {
//创建构造器
class Person(var name:String = "",var age:Int = 0){
}
def main(args: Array[String]): Unit = {
var p = new Person("zhangsan",17)
println(p.name)
println(p.age)
}
}
辅助构造器
1.除了主构造器之外的构造器称为辅助构造器。
2.定义辅助构造器与定义方法一样,也使用def关键字来定义
3.这个方法的名字为this
4.辅助构造器的第一行代码,必须要调用主构造器或者其他辅助构造器
格式:
def this(参数名:类型, 参数名:类型) {
// 第一行需要调用主构造器或者其他构造器
// 构造器代码
}
例:
object demo03 {
//创建构造器
class Person(var name:String = "",var address:String = ""){
//创建辅助构造器
def this(arr:Array[String]){
this(arr(0),arr(1))
}
}
def main(args: Array[String]): Unit = {
//实例化对象
var p = new Person(Array("zhangsan","北京"))
println(p.name)
println(p.address)
}
}
-
单例对象
1.scala中没有Java中的静态成员,若想要定义类似于Java的static变量、static方法,就要使用到scala中的单例对象——object.
2.单例对象表示全局仅有一个对象(类似于Java static概念)
3.定义单例对象和定义类很像,就是把class换成object
4.在object中定义的成员变量类似于Java的静态变量
5.可以使用object直接引用成员变量
例:
object demo04 {
//创建单例对象
object Person {
var name: String = "zhangsan"
}
def main(args: Array[String]): Unit = {
println(Person.name)
}
}
在单例对象中定义成员方法
1.在object中定义的成员方法类似于Java的静态方法
例:
object demo04 {
//创建单例对象
object Person {
var name: String = "zhangsan"
//定义成员方法
def show() = {
println("show")
}
}
def main(args: Array[String]): Unit = {
println(Person.name)
//调用方法
Person.show()
}
}
-
main方法
scala和Java一样,如果要运行一个程序,必须有一个main方法。在Java中main方法是静态的,而在scala中没有静态方法。在scala中,这个main方法必须放在一个单例对象中。
格式:
def main(args:Array[String]):Unit = {
// 方法体
}
实现App Trait来定义入口
创建一个object,继承自App Trait(特质),然后将需要编写在main方法中的代码,写在object的构造方法体内。
格式:
object 单例对象名 extends App {
// 方法体
}
例:
object demo05 extends App {
println("holle")
}
-
伴生对象
1.一个class和object具有同样的名字。这个object称为伴生对象,这个class称为伴生类
2.伴生对象必须要和伴生类一样的名字
3.伴生对象和伴生类在同一个scala源文件中
4.伴生对象和伴生类可以互相访问private属性
例:
object demo06 {
class Person{
private val id:String = "123"
//可以互相访问私有数据
println(Person.name)
}
object Person{
private var name:String = "zhangsan"
//可以互相访问私有数据
println(new Person().id)
}
def main(args: Array[String]): Unit = {
}
}
private[this]访问权限
如果某个成员的权限设置为private[this],表示只能在当前类中访问。伴生对象也不可以访问
例:
object demo06 {
class Person{
private[this] val id:String = "123"
//可以互相访问私有数据
println(Person.name)
}
object Person{
private var name:String = "zhangsan"
//被private[this]修饰 不能访问 报错
//println(new Person().id)
}
def main(args: Array[String]): Unit = {
}
}
-
继承
1.scala语言是支持面向对象编程的, 可以使用scala来实现继承,通过继承来减少重复代码
2.使用extends关键字来实现继承
3.可以在子类中定义父类中没有的字段和方法,或者重写父类的方法
4.类和单例对象都可以从某个父类继承
格式:
class/object 子类 extends 父类 {
..
}
例:
//父类
class Person {
var name:String = "zhangsan"
def getName(): Unit ={
this.name
}
}
object demo07 {
//子类
class Stu extends Person{
}
def main(args: Array[String]): Unit = {
var stu = new Stu();
//调用父类的方法
println(stu.name)
}
}
-
override和super
1.类似于Java语言, 在子类中使用override需要来重写父类的成员,可以使用super来引用父类
2.子类要覆盖父类中的一个方法,必须要使用override关键字
3.使用override来重写一个val字段
4.使用super关键字来访问父类的成员方法
例:
//父类
class Person {
val name = "super"
def getName = name
}
object demo07 {
class Student extends Person {
// 重写val字段
override val name: String = "child"
// 重写getName方法
override def getName: String = "hello, " + super.getName
}
def main(args: Array[String]): Unit = {
var stu = new Student();
println(stu.name)
println(stu.getName)
}
}
-
类型判断
有时候,我们设计的程序,要根据变量的类型来执行对应的逻辑
isInstanceOf/asInstanceOf
1.isInstanceOf判断对象是否为指定类以及其子类的对象
2.asInstanceOf将对象转换为指定类型
格式:
// 判断对象是否为指定类型
val trueOrFalse:Boolean = 对象.isInstanceOf[类型]
// 将对象转换为指定类型
val 变量 = 对象.asInstanceOf[类型]
例:
//父类
class Person {
val name = "super"
def getName = name
}
object demo07 {
//子类
class Student extends Person {
// 重写val字段
override val name: String = "child"
// 重写getName方法
override def getName: String = "hello, " + super.getName
}
def main(args: Array[String]): Unit = {
var stu1 = new Student();
var stu2:Person = new Student();
//判断对象是否为指定类型 true
println(stu1.isInstanceOf[Student])
//将对象转换为指定类型 将Person类型转为Student类型
if (stu2.isInstanceOf[Student]){
val s2 = stu2.asInstanceOf[Student]
println(s2)
}
}
}
getClass/classOf
1.isInstanceOf 只能判断对象是否为指定类以及其子类的对象,而不能精确的判断出,对象就是指定类的对象。如果要求精确地判断出对象就是指定类的对象,那么就只能使用 getClass 和 classOf 。
2.p.getClass可以精确获取对象的类型(不是父类)
3.classOf[x] 可以指定精确类型
4.使用==操作符可以直接比较类型
例:
class Person {
val name = "super"
def getName = name
}
object demo07 {
class Student extends Person {
// 重写val字段
override val name: String = "child"
// 重写getName方法
override def getName: String = "hello, " + super.getName
}
def main(args: Array[String]): Unit = {
var stu = new Student();
//true
println(stu.getClass() == classOf[Student])
//false//抽象类
abstract class Shape {
//抽象字段
var r:Double
//抽象方法
def area(): Double
}
//子类1 正方形
class Square(edge: Double) extends Shape {
//实现字段
override var r: Double = edge;
//实现方法
override def area(): Double = {
r * r
}
}
//子类2 圆形
class Roundness(radius: Double) extends Shape {
//实现字段
override var r: Double = radius
//实现方法
override def area(): Double = {
r * r * 3.14
}
}
def main(args: Array[String]): Unit = {
//正方形
var square = new Square(10);
println(square.area())
//圆形
var roundness = new Roundness(10);
println(roundness.area())
}
println(stu.getClass() == classOf[Person])
}
}
-
抽象类
1.如果类的某个成员在当前类中的定义是不包含完整的,它就是一个抽象类
2.不完整定义有两种情况:
a.方法没有方法体(抽象方法)
b.变量没有初始化(抽象字段)
3.定义抽象类和Java一样,在类前面加上abstract关键字
4.在抽象类中不抽象的字段或方法不用重写
格式:
// 定义抽象类
abstract class 抽象类名 {
// 定义抽象字段
val 抽象字段名:类型
// 定义抽象方法
def 方法名(参数:参数类型,参数:参数类型...):返回类型
}
例:
//抽象类
abstract class Person {
//抽象字段
var name: String
//抽象方法
def Say(msg:String):String
}
//抽象类
abstract class Shape {
//抽象字段
var r:Double
//抽象方法
def area(): Double
}
//子类1 正方形
class Square(edge: Double) extends Shape {
//实现字段
override var r: Double = edge;
//实现方法
override def area(): Double = {
r * r
}
}
//子类2 圆形
class Roundness(radius: Double) extends Shape {
//实现字段
override var r: Double = radius
//实现方法
override def area(): Double = {
r * r * 3.14
}
}
//main方法
def main(args: Array[String]): Unit = {
//正方形
var square = new Square(10);
println(square.area())
//圆形
var roundness = new Roundness(10);
println(roundness.area())
}
-
匿名内部类
匿名内部类是没有名称的子类,直接用来创建实例对象。Spark的源代码中有大量使用到匿名内部类。scala中的匿名内部类使用与Java一致。
格式:
val/var 变量名 = new 类/抽象类 {
// 重写方法
}
例:
//抽象类
abstract class Shape {
//抽象字段
var r: Double
//抽象方法
def area(): Double
}
//main方法
def main(args: Array[String]): Unit = {
//匿名内部类
var dd = new Shape {
//重写字段
override var r: Double = 10
//重写方法
override def area(): Double = {
r
}
}
//打印
println(dd.area)
}
}
-
特质(trait)
1.scala中没有Java中的接口(interface),替代的概念是特质
2.特质是scala中代码复用的基础单元
3.它可以将方法和字段定义封装起来,然后添加到类中
4.与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。
5.特质的定义和抽象类的定义很像,但它是使用trait关键字
6.使用extends来继承trait(scala不论是类还是特质,都是使用extends关键字)
7.如果要继承多个trait,则使用with关键字
8.在trait中可以定义具体字段和抽象字段
9.scala中可以将trait混入到对象中,就是将trait中定义的方法、字段添加到一个对象中
10.trait也可以继承class的。特质会将class中的成员都继承下来
格式:
//定义特质
trait 名称 {
// 抽象字段
// 抽象方法
}
//继承特质
class 类 extends 特质1 with 特质2 {
// 字段实现
// 方法实现
}
继承单个特质
例:
//特质
trait Person {
//完整字段 不需要被继承
var id: String = "123456"
//抽象字段
var name: String
//完整方法 不需要被继承
def SayHello(msg: String) = {
println(msg)
}
//抽象方法
def Say(): String
}
//子类
class Stuent extends Person {
//实现父类字段
override var name: String = "张三"
//实现父类方法
override def Say(): String = {
name
}
}
继承多个特质
例:
//特质1
trait Person1 {
//完整字段 不需要被继承
var id: String = "123456"
//抽象字段
var name: String
//完整方法 不需要被继承
def SayHello(msg: String) = {
println(msg)
}
//抽象方法
def Say(): String
}
//特质2
trait Person2 {
//抽象方法
def doing(): String
}
//子类 继承Person1 Person2两个特质
class Student extends Person1 with Person2 {
//实现父类Person1字段
override var name: String = "张三"
//实现父类Person1方法
override def Say(): String = {
name
}
//实现父类Person2方法
override def doing(): String = {
name
}
}
object继承trait
例:
//特质
trait Sum2 {
//抽象方法
def sum(num1: Int, num2: Int): Unit
}
//子object
object Sums extends Sum2 {
//重写方法
override def sum(num1: Int, num2: Int): Unit = {
println(num1 + num2)
}
}
//main方法
def main(args: Array[String]): Unit = {
//调用方法
Sums.sum(10,10)
}
使用trait实现模板模式
在一个特质中,具体方法依赖于抽象方法,而抽象方法可以放到继承trait的子类中实现,这种设计方式也称为模板模式
例:
//特质
trait Logger {
//抽象方法
def log(msg: String): Unit
//创建具体方法并调用抽象方法
def info(msg: String) = log("Info" + msg)
def warn(msg: String) = log("Warn" + msg)
def error(msg: String) = log("Error" + msg)
}
//继承特质
class ConsoleLogger extends Logger {
//现抽象方法
override def log(msg: String): Unit = {
println(msg)
}
}
def main(args: Array[String]): Unit = {
var log = new ConsoleLogger();
//调用方法
log.info("信息日志")
log.warn("警告日志")
log.error("错误日志")
}
对象混入trait
scala中可以将trait混入到对象中,就是将trait中定义的方法、字段添加到一个对象中
格式:
val/var 对象名 = new 类 with
例:
//特质
trait Do {
def say(msg: String): String = {
println(msg + "1")
msg
}
def say1():String
}
//类
class Student
//main方法
def main(args: Array[String]): Unit = {
//创建对象 混入trait
var stu = new Student() with Do {
//实现抽象方法
override def say1(): String = {
"lisi"
}
}
//调用方法
stu.say("zhangsan")
println( stu.say1())
}
trait实现调用链模式
类继承了多个trait后,可以依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法在最后都依次执行super关键字即可。类中调用多个tait中都有这个方法时,首先会从最右边的trait方法开始执行,然后依次往左执行,形成一个调用链条。
例:
//特质1
trait HandlerTrait {
def handler(msg: String) = {
println("第四步:打印数据" + msg)
}
}
//特质2 继承特质1
trait DataValidHandlerTrait extends HandlerTrait {
//重写方法
override def handler(msg: String): Unit = {
println("第三步:验证数据" + msg)
//调用父类方法
super.handler(msg)
}
}
//特质3 继承特质1
trait SignatureValidHandlerTrait extends HandlerTrait {
//重写方法
override def handler(msg: String): Unit = {
println("第二步:检查签名" + msg)
//调用父类方法
super.handler(msg)
}
}
//子类 继承特质1 特质2
class PaymentService extends DataValidHandlerTrait with SignatureValidHandlerTrait {
def pay(msg: String) = {
println("第一步:准备支付" + msg)
super.handler(msg)
}
}
//main方法
def main(args: Array[String]): Unit = {
var paymentService = new PaymentService();
paymentService.pay("牛奶")
}
trait继承class
trait也可以继承class的。特质会将class中的成员都继承下来
//父类
class MyUtils {
def printMsg(msg: String) = {
println(msg)
}
}
//子特质
trait Logger extends MyUtils {
def log(msg: String) = printMsg(msg)
}
//特质的子类
class Person extends Logger {
def Say(msg: String) = log(msg)
}
//main方法
def main(args: Array[String]): Unit = {
var person = new Person();
//调用方法 Person子类可以调用父类所有方法
person.Say("zhangsan");
person.log("lisi")
person.printMsg("wangwu")
}
-
样例类
样例类是一种特殊类,它可以用来快速定义一个用于保存数据的类(类似于Java POJO类),在后续要学习并发编程和spark、flink这些框架也都会经常使用它。
格式:
case class 样例类名([var/val] 成员变量名1:类型1, 成员变量名2:类型2, 成员变量名3:类型3)
例:
//样例类 默认的字段为常量
case class Student(var name: String, age: Int) {
}
//main方法
def main(args: Array[String]): Unit = {
//创建样例类对象 不需要new
var student = Student("张三", 17)
//重赋值数据 如果数据为变量(var)则可以重新赋值
student.name = "李四"
//打印数据
println(student.name)
println(student.age)
}
常用方法
apply:apply方法可以让我们快速地使用类名来创建对象
toString:toString返回样例类名称(成员变量1, 成员变量2, 成员变量3....)
equals:样例类自动实现了equals方法,可以直接使用==比较两个样例类是否相等,即所有的成员变量是否相等
hashCode:样例类自动实现了hashCode方法,如果所有成员变量的值相同,则hash值相同,只要有一个不一样,则hash值不一样。
copy:样例类实现了copy方法,可以快速创建一个相同的实例对象,可以使用带名参数指定给成员进行重新赋值
-
样例对象
1.定义枚举
2.作为没有任何参数的消息传递
格式:
case object 样例对象名
例:
object Test02 {
//特质
trait sex
//定义特质的枚举
case object Boy extends sex
case object Girl extends sex
//创建对象 对象的一个属性设置为枚举
case class Person(name: String, sex: sex)
def main(args: Array[String]): Unit = {
//创建对象
var person = Person("张三", Boy)
}
}