/*
关键字:class
创建对象:new
内含:成员变量和方法
区别:
1、默认访问修饰符为 public,也支持 private 和 protected
2、没有构造方法,通过构造参数列表实现对象创建
*/
// 主构造器
class Point(x:Int,y:Int) {
var _x:Int = x
var _y:Int = y
def move(offsetX:Int,offsetY:Int): Unit = {
_x += offsetX
_y += offsetY
}
override def toString: String = s"Point{x=${_x},y=${_y}}"
}
val p = new Point(0,0)
p.move(15,32)
p.x
p.y
修饰符
类(class)
伴生对象(object)
子类(subclass)
同包(package)
全局(world)
default(public)
Y
Y
Y
Y
Y
protected
Y
Y
Y
N
N
private
Y
Y
N
N
N
Scala复制代码
// 辅助构造器:基于主构造器的重载
class Student(name:String,age:Int) {
private var _name:String = name
private var _age:Int = age
// 辅助构造器
def this() = this("Unknown",0)
def this(name:String) = this(name,18)
def getName:String = _name
def getAge:Int = _age
def setName(name:String):Unit = _name = name
def setAge(age:Int):Unit = _age = age
override def toString(): String = s"Student{name=${_name},age=${_age}}"
}
val stu1 = new Student("张三", 20)
val stu2 = new Student()
val stu3 = new Student("henry")
继承
Scala复制代码
/*
extends & override
*/
class ColorPoint(x:Int,y:Int,color:Boolean) extends Point(x:Int,y:Int) {
var _color:Boolean = color
private def getColor = if(_color) "red" else "black"
override def move(offsetX: Int, offsetY: Int): Unit = {
_x += offsetX*2
_y += offsetY*2
println(s"$getColor point moved to {${_x},${_y}}")
}
override def toString: String = s"$getColor point ${super.toString}"
}
val cp = new ColorPoint(0,0,true)
println(cp)
cp.move(12,25)
/*
red point now at {0,0}
red point moved to {24,50}
*/
抽象类
Scala复制代码
/*
abstract & extends & override
抽象类中可以有抽象方法(没有方法体的方法即抽象方法)
无法实例化
使用 abstract 关键字修饰
子类重写父类【抽象】方法可以省略 override 关键字,但不推荐省略
子类重写父类【非抽象】方法必须写 override 关键字
*/
abstract class Shape {
def draw():Unit // 抽象方法
}
class Circle extends Shape{
override def draw(): Unit = {
println("drawing a circle")
}
}
val shape = new Circle
shape.draw()
单例对象
Scala复制代码
/*
代替 Java 中的 static 关键字
1、关键字:object
2、可以包含属性和方法,且可以通过单例对象名直接调用
3、采取惰性模式,第一次被访问时创建
4、无构造器,且不能 new
5、程序入口方法必须定义在单例对象中
6、同一个文件中同名的类和单例对象形成绑定关系,并称之为伴生类和伴生对象
*/
// 文件名:Student.scala
// 伴生类
class Student(name:String,age:Int) {
private var _name:String = name
private var _age:Int = age
def this() = this("Unknown",0)
def this(name:String) = this(name,18)
def getName:String = _name
def getAge:Int = _age
def setName(name:String):Unit = _name = name
def setAge(age:Int):Unit = _age = age
override def toString(): String = s"Student{name=${_name},age=${_age}}"
}
// 伴生对象
object Student{
var products:Array[String] = Array("BigData","Cloud")
def apply(name: String, age: Int): Student = new Student(name, age)
def add(a:Int,b:Int) = a+b
}
Student.products.foreach(println)
val rst: Int = Student.add(2, 3)
val stu1 = new Student("张三", 20)
// 自动调用 apply 完成 Student 对象构造
val stu2 = Student("ariel",22)
/*
【 练习一 】
需求说明
假设类Book有属性title和author(多个),books是Book的列表
实现Book类,同时使用主构造器与辅助构造器
实现Book的伴生对象,使用伴生对象创建Book实例
创建books,使用List[Book]初始化5个以上Book实例
找出books中书名包含"xxx"的书,并打印书名
找出books中作者名以"xxx"打头的书,并打印书名
*/
val list = List(
Book("武侠:最强小保安",Array("张三","李四","王五")),
Book("都市:上门赘婿",Array("阿强","洞冥福","花花")),
Book("武侠:翔龙会",Array("阿庆嫂","黄世仁")),
Book("都市:缘起",Array("徐世明","张丘月")),
Book("武侠:小李飞刀",Array("王栋","李宏","张明")),
)
特质
Scala复制代码
/*
is a : extends
has a : implements|with
关键字:trait & extends & with & override
1、包含字段、方法,亦可包含字段和方法的实现
2、类、单例对象、普通对象都可以扩展特质
3、没有构造器,不能实例化
4、单根继承,借助 with 实现多混入
*/
abstract class Animal {
val info:String = "动物描述类"
val name:String
def showMe:Unit = println(s"This is dog $name")
def cry():Unit
}
trait ByFoot {
def jog():Unit
def run():Unit
}
class Dog(dogName:String) extends Animal {
override val name: String = dogName
override def cry(): Unit = println(s"Dog $name is crying...")
}
object Dog{
def apply(dogName: String): Dog = new Dog(dogName)
}
object Cat extends Animal with ByFoot {
override val name: String = "加云"
override def cry(): Unit = println(s"Cat $name is crying...")
override def jog(): Unit = println(s"Cat $name is jogging...")
override def run(): Unit = println(s"Cat $name is running...")
}
val xq = Dog("小强")
xq.cry()
val jy = Cat
jy.cry()
jy.jog()
jy.run()
动态混入
Scala复制代码
// 动态强制混入特质:只能定义一个强制混入特质,且必须位于类内首行
// self 是 this 的别名
class Penguin {
self:Animal=> // 强制混入特质语法
val brand:String = "企鹅"
}
// 复合类型 Penguin with Animal
val penguin: Penguin with Animal = new Penguin() with Animal {
override val name: String = "阿童木"
override def cry(): Unit = println(s"$brand $name is crying")
}
penguin.cry()
// 动态非强制混入特质 with,支持多混入
class Bear(nickName:String) {
val _name:String = nickName
}
val bear: Bear = new Bear("熊大") with Animal with ByFoot {
override val name: String = "狗熊"
override def cry(): Unit = println(s"$name ${_name} is crying")
override def jog(): Unit = println(s"$name ${_name} is jogging")
override def run(): Unit = println(s"$name ${_name} is running")
}
bear.cry()
bear.jog()
bear.run()
/*
Java中内部类是【外部类的成员】:
InClass ic = new OutClass.InClass()
Scala中内部类是【外部类对象的成员】:
val oc = new OutClass();
val ic = new oc.InClass();
*/
class OutClass(name:String,age:Int,gender:String,school:String,major:String) {
class InnerClass(age:Int,gender:String){
private var _age:Int = age
private var _gender:String = gender
def getAge = _age
def getGender = _gender
def setAge(age:Int) = _age = age
def setGender(gender:String) = _gender = gender
}
private val _name:String = name
private var _in:InnerClass = new InnerClass(age, gender)
var _in2:OutClass.Inner2Class = new OutClass.Inner2Class(school, major)
def setAge(age:Int) = _in.setAge(age)
def setGender(gender:String) = _in.setGender(gender)
def setIn(in:InnerClass) = _in = in
def setIn2(in2:OutClass.Inner2Class) = _in2 = in2
override def toString: String =
s"${_name},${_in.getAge},${_in.getGender},${_in2._school},${_in2._major}"
}
object OutClass{
class Inner2Class(school:String,major:String){
val _school:String = school
val _major:String = major
}
}
val oc = new OutClass("henry",22,"male","南邮","通信")
oc.setAge(33)
oc.setGender("female")
val in = new oc.InnerClass(30, "female") // 外部类对象.内部类(...)
oc.setIn(in)
val in2 = new OutClass.Inner2Class("南信大","人工智能")
oc.setIn2(in2)
样例类
Scala复制代码
/*
描述【不可变值】的对象
样例类构造参数默认声明为 val,自动生成 getter
样例类的构造参数若声明为 var,自动生成 getter & setter
样例类自动生成伴生对象
样例类自动实现的其他方法:toString,copy,equals,hashCode
样例类伴生对象实现的方法:apply, unapply(用于模式匹配)
*/
// 普通类的模式匹配案例
case class Student(name:String, age:Int) // 构造参数默认 val
case class Point(var x:Int,var y:Int) // var 需要显式声明
val obj:Any = Student("henry",18)
val info = obj match {
case Student(_,22) => "22"
case Student(name,_) if name.startsWith("张") => "姓张"
case Point(a,_) => s"$a" // 报错 cannot resolve symbol
}
// 追加伴生对象并实现 apply & unapply 之后,不再报错
object Point{
def apply(x: Int, y: Int): Point = new Point(x, y)
def unapply(arg: Point): Option[(Int, Int)] = Some((arg._x,arg._y))
}
枚举
Scala复制代码
/*
单例对象通过继承 Enumeration 实现枚举创建,简单易用,但不可扩展
通常用于定义一个有限取值范围的常量
*/
object WeekDay extends Enumeration {
val MON = Value(0)
val TUE = Value(1)
val WEN = Value(2)
val THU = Value(3)
val FRI = Value(4)
val SAT = Value(5)
val SUN = Value(6)
}
val wd = WeekDay.WEN
val info = wd match {
case WeekDay.MON => "星期一"
case WeekDay.TUE => "星期二"
case WeekDay.WEN => "星期三"
case _ => "不需要"
}
泛型
Scala复制代码
/*
类型参数化,主要用于集合
不同于 Java 泛型被定义在 [] 中
*/
class GrandFather(name:String) {
val _name:String = name
override def toString: String = _name
}
object GrandFather{
def apply(name: String): GrandFather = new GrandFather(name)
}
class Father(name:String) extends GrandFather(name:String) {}
object Father{
def apply(name: String): Father = new Father(name)
}
class Son(name:String) extends Father(name:String) {}
object Son{
def apply(name: String): Son = new Son(name)
}
class GrandSon(name:String) extends Son(name:String){}
object GrandSon{
def apply(name: String): GrandSon = new GrandSon(name)
}
/*
泛型边界定义
上边界:T<:A 泛型为某个类型的子类
下边界:T>:A 泛型为某个类型的父类
*/
class MyArray[T <: Father](items:T*) {
def join(sep:String) = items.mkString(sep)
}
// Type GrandFather does not conform to 【 upper bound 】 Father of type parameter T
val arr:MyArray[GrandFather] = ...
class MyArray[T >: Son](items:T*) {
def join(sep:String) = items.mkString(sep)
}
// Type GrandSon does not conform to 【 lower bound 】 Son of type parameter T
val arr:MyArray[GrandSon] = ...
/*
型变:多态
协变:[+T] 若A是B的子类,则 C[A]为C[B]的子类
逆变:[-T] 若A是B的子类,则 C[B]为C[A]的子类
不变:[T] 默认
*/
class MyArray[+T](items:T*) {
def join(sep:String) = items.mkString(sep)
}
// Father 是 Son 的父类,则 MyArray[Father] 就是 MyArray[Son] 的父类
val arr:MyArray[Father] = new MyArray[Son](Son("henry"),Son("ariel"))
class MyArray[-T](items:T*) {
def join(sep:String) = items.mkString(sep)
}
// Father 是 Son 的子类,则 MyArray[Son] 就是 MyArray[Father] 的子类
val arr:MyArray[Son] = new MyArray[Father](Son("henry"),Son("ariel"))
class MyArray[T](items:T*) {
def join(sep:String) = items.mkString(sep)
}
// 所有泛型都必须为 Son
val arr:MyArray[Son] = new MyArray[Son](Son("henry"),Son("ariel"))
包与包对象
Scala复制代码
/*
【包】
包命名规则:字母、数字、下划线、点,不能以数字开头,在【一个类文件中可以定义多个并列的包】
导包的不同方式
import com.kgc.Person 方便使用类 Person
import com.kgc._ 方便使用 com.kgc 包中的所有类
import com.kgc.Person._ 方便使用类 Person 中的所有属性和方法
import com.kgc.{Person=>PS,Book} 只导入包中 Person和Book,并将Person重命名为PS
不同于Java
import 导包语句可以出现在任意地方
可以导入包、类、类成员
*/
// 单个文件多包结构:资源按包名语义分类存放,方便管理和使用
----------------------- Test.scala START ----------------------------
package cha03{
import cha03.util.Sorts
object PackageTest {
def main(args: Array[String]): Unit = {
val array: Array[Int] = Array(3, 1, 5, 4, 2)
Sorts.insertSort(array)
array.foreach(println)
}
}
}
package cha03.util{
object Sorts{
def insertSort(array: Array[Int]): Unit ={
import scala.util.control.Breaks._
for(i<- 1 until array.length){
val t = array(i)
var j = i-1
breakable({
while (j>=0){
if(array(j)>t){
array(j+1) = array(j)
}else{
break()
}
j-=1
}
})
array(j+1) = t
}
}
}
}
----------------------- Test.scala END ----------------------------
/*
【包对象】
包中可以包含:类、对象、特质...
包对象可以包含:除了类、对象、特质外,还可以包含变量和方法
*/
package cha03{
import cha03.util.Constants._
import cha03.util.Constants.{DataFormat=>DF}
object PackageTest {
def main(args: Array[String]): Unit = {
println(PI*2*2)
println(getQuarter(5))
val format: DF = DF(2024, 3, 29)
println(format.stdYMD())
println(format.stdFull())
println(format.timestamp())
}
}
}
package cha03.util{
import java.util.Calendar
// 包对象
package object Constants{
// 变量
val PI:Float = 3.14f
// 方法
def getQuarter(month:Int)=(month-1)/3+1
// 类
class DataFormat(
year:Int,month:Int,day:Int,
hour:Int,minute:Int,second:Int,
millis:Int){
private var _year:Int = year
private var _month:Int = month
private var _day:Int = day
private var _hour:Int = hour
private var _minute:Int = minute
private var _second:Int = second
private var _millis:Int = millis
def this(year:Int,month:Int,day:Int){
this(year,month,day,0,0,0,0)
}
def stdYMD():String = s"${_year}-${_month}-${_day}"
def stdFull():String = s"${_year}-${_month}-${_day} ${_hour}:${_minute}:${_second}.${_millis}"
def timestamp():Long = {
val cld = Calendar.getInstance()
cld.set(_year,_month,_day,_hour,_minute,_second)
cld.set(Calendar.MILLISECOND,555)
cld.getTimeInMillis
}
}
}
object DataFormat{
def apply(year: Int, month: Int, day: Int,
hour: Int, minute: Int, second: Int, millis: Int): DataFormat
= new DataFormat(year, month, day, hour, minute, second, millis)
def apply(year: Int, month: Int, day: Int): DataFormat
= new DataFormat(year, month, day)
}
}
// 导包
import pack_name
import pack_name._
import pack_name.{A=>AS,B}
import pack_name.Class
import pack_name.Class.{PI,show}
import pack_name.Class._