第6章 面向对象
6.1. Scala包
-
包的命名
-
包的导入
-
Scala中基本的import导入语法和Java完全一致
import java.util.List import java.util._ // Scala中使用下划线代替Java中的星号
-
Java中import导入的语法比较单一,Scala对此进行扩展,Scala中的import语法可以在任意位置使用
object ScalaImport{ def main(args: Array[String]): Unit = { import java.util.ArrayList new ArrayList() } }
-
Scala中可以导包,而不是导类
object ScalaImport{ def main(args: Array[String]): Unit = { import java.util new util.ArrayList() } }
-
Scala中可以在同一行中导入多个类,简化代码
import java.util.{List, ArrayList}
-
Scala中可以屏蔽某个包中的类
import java.util._ import java.sql.{ Date=>_, Array=>_, _ }
-
Scala中可以给类起别名,简化使用
import java.util.{ArrayList=>AList} object ScalaImport{ def main(args: Array[String]): Unit = { new AList() } }
-
Scala中可以使用类的绝对路径而不是相对路径
import _root_.java.util.ArrayList
-
默认情况下,Scala中会导入如下包和对象
import java.lang._ import scala._ Import scala.Predef._
-
6.2 类和对象
-
类和对象
package chapter06 import scala.beans.BeanProperty object Test03_Class { def main(args: Array[String]): Unit = { val student = new Student() // println(student.name) // 不能访问private属性 println(student.age) println(student.sex) student.sex = "male" println(student.sex) } } // 定义一个类 class Student{ // 定义属性 // 生成get和set方法 private var name: String = "Alice" // 初值为空, 0,必须定义var @BeanProperty var age: Int = _ // 初值为空, null,必须定义var @BeanProperty var sex: String = _ }
-
封装
-
访问权限
package chapter06 import scala.beans.BeanProperty object Test04_Access { def main(args: Array[String]): Unit = { // 创建对象 val person = new Person() // person.idCard // error // person.name // error println(person.sex) println(person.age) person.printInfo() val worker = new Worker() // worker.idCard // error // worker.name // error println(worker.sex) println(worker.age) worker.printInfo() } } // 定义一个子类 class Worker extends Person { override def printInfo(): Unit = { println(s"Worker:") // println($idCard) // error name = "bob" age = 25 sex = "male" println(s"Worker: $name ${sex} $age") } }
package chapter06 object Test04_ClassForAccess { } // 定义一个父类 class Person { // 只能在当前类访问和伴生对象访问 private var idCard: String = "123456" // 只能在当前类和子类访问 protected var name: String = "Alice" var sex: String = "female" private[chapter06] var age: Int = 18 def printInfo() = { println(s"Person: $idCard $name ${sex} $age") } }
-
构造器
和类名一样的方法
package chapter06 object Test05_Constructor { def main(args: Array[String]): Unit = { val student1 = new Student1() student1.Student1() val student2 = new Student1("scc") student2.Student1() val student3 = new Student1("zyy", 18) student3.Student1() } } // 定义一个类 class Student1() { var name: String = _ var age: Int = _ println(s"1. 主构造方法被调用 $name $age") // 声明辅助构造方法 def this(name: String) = { this() // 直接调用主构造器 println(s"2. 辅助构造方法一被调用 $name $age") this.name = name println(s"name: $name age: $age") } def this(name: String, age: Int) = { this(name) // 直接调用辅助构造器一 println(s"3. 辅助构造方法二被调用 $name $age") this.name = name this.age = age println(s"name: $name age: $age") } // 此处不是构造方法 def Student1() = { println(s"一般方法被调用") } }
1. 主构造方法被调用 null 0 一般方法被调用 1. 主构造方法被调用 null 0 2. 辅助构造方法一被调用 scc 0 name: scc age: 0 一般方法被调用 1. 主构造方法被调用 null 0 2. 辅助构造方法一被调用 zyy 0 name: zyy age: 0 3. 辅助构造方法二被调用 zyy 18 name: zyy age: 18 一般方法被调用
-
构造器参数
package chapter06 object Test06_ConstructorParams { def main(args: Array[String]): Unit = { val student2 = new Student2 student2.name = "Alice" student2.age = 18 println(s"student2 name: ${student2.name}, age: ${student2.age}") val student3 = new Student3("scc", 18) println(s"student3 name: ${student3.name}, age: ${student3.age}") val student4 = new Student4("bob", 29) println(s"student4 name: ${student4.name}, age: ${student4.age}") val student6 = new Student6("bob", 29,"南京理工") student6.printInfo println(s"student6 name: ${student6.name}, age: ${student6.age}") } } // 定义一个类 // 无参构造器 class Student2() { // 单独定义属性 var name: String = _ var age: Int = _ } // 主构造器参数有var修饰,上面定义等价于,name和age为属性,不需要new和单独赋值,推荐这种写法 class Student3(var name: String, var age: Int) // 主构造器参数无修饰,此时_name和_age为形参 // 非常不推荐 class Student4(_name: String, _age: Int) { var name = _name var age = _age } // val 属性值不能修改 class Student5(val name: String, val age: Int) // 主构造器有参数 class Student6(var name: String, var age: Int) { var school: String = _ def this(name: String, age: Int, school: String) = { // 先调用主构造器有参数 this(name, age) // 先调用辅助构造器有参数 this.school = school } def printInfo = { println(s"student6 name: ${this.name}, age: ${this.age}, school: ${this.school}") } }
-
继承
package chapter06 object Test07_Inherit { def main(args: Array[String]): Unit = { /** * 1. 父类的主构造器调用 * 2. 父类的辅助构造器调用 * 3. 子类的主构造器被调用 */ val student1 = new Student7("scc", 18) /** * 1. 父类的主构造器调用 * 2. 父类的辅助构造器调用 * 3. 子类的主构造器被调用 * 4. 子类的辅助构造器被调用 */ val student2 = new Student7("scc", 18, "0001") } } // 定义一个父类 class Person7() { var name: String = _ var age: Int = _ println("1. 父类的主构造器调用") def this(name: String, age: Int) = { this() println("2. 父类的辅助构造器调用") this.name = name this.age = age } def printInfo = { println(s"Person7: $name $age") } } // 定义一个子类 // name和age为构造器参数,不是属性 // extends Person7(name, age) 和 extends Person7不一样,后者不会调用辅助构造器 class Student7(name: String, age: Int) extends Person7(name, age) { var studentNum: String = _ println("3. 子类的主构造器被调用") def this(name: String, age: Int, studentNum: String) = { // 调用主构造器,先调用父类构造器,再调用子类构造器 this(name, age) println("4. 子类的辅助构造器被调用") this.studentNum = studentNum } override def printInfo: Unit = { println(s"Student7: $name $age $studentNum") } }
-
多态
定义:一种接口,可以有多种实现方式
通过运行时,动态绑定手段,实现多态
scala属性和方法都是动态绑定的
-
抽象类
package chapter06 object Test09_Abstract { def main(args: Array[String]): Unit = { val student = new Student9 student.eat() student.sleep() } } // 定义抽象类 abstract class Person9() { //非抽象属性 val name: String = "person" // 抽象属性 var age: Int // 非抽象方法 def eat(): Unit = { println("person eat") } // 抽象方法 def sleep(): Unit } // 定义具体的实现子类 class Student9 extends Person9 { // 实现抽象属性和方法 override var age: Int = 18 override def sleep(): Unit = { println("student sleep") } //实现非抽象属性和方法,此时name在父类中是val类型 override val name: String = "student" override def eat(): Unit = { super.eat() println("student eat") } }
-
匿名子类
package chapter06 // 匿名子类 object Test10_AnnoymousSubClass { def main(args: Array[String]): Unit = { val person: Person10 = new Person10 { override var name: String = "scc" override def eat(): Unit = { println(s"${name} eat!") } } println(person.name) person.eat() } } // 定义抽象类 abstract class Person10 { var name: String def eat(): Unit }
-
单例对象/伴生对象
package chapter06 object Test11_Object { def main(args: Array[String]): Unit = { // 1. private 构造方法私有化时,下面语句会报错 // val student = new Student11("alice", 18) // student.printInfo() val student1: Student11 = Student11.newStudents("alice", 19) student1.printInfo() val student2: Student11 = Student11.apply("scc", 19) student2.printInfo() // 调用时,可以直接省略apply val student3: Student11 = Student11("zyy", 19) student3.printInfo() } } // 定义类,private 构造方法私有化 class Student11 private(val name: String, val age: Int) { def printInfo(): Unit = { println(s"student name: ${name}, age: ${age}, school: ${Student11.school}") } } // 定义伴生对象 object Student11 { val school: String = "atguigu" // 定义一个类的对象实例的创建方法或者工厂方法 def newStudents(name: String, age: Int): Student11 = { new Student11(name, age) } // 定义一个特殊的方法,此方法有个特殊用法,调用时,可以直接省略apply def apply(name: String, age: Int): Student11 = { new Student11(name, age) } }
-
单例设计模式
饿汉式和懒汉式
package chapter06 object Test12_Singleton { def main(args: Array[String]): Unit = { val student1 = Student12.getInstance() student1.printInfo() // 真的只有一份吗?不信,再执行一遍 val student2 = Student12.getInstance() student2.printInfo() println(student1) println(student2) println(student1.eq(student2)) } } // 定义类,private 构造方法私有化 class Student12 private(val name: String, val age: Int) { def printInfo(): Unit = { println(s"student name: ${name}, age: ${age}, school: ${Student11.school}") } } // 定义伴生对象 // 单例设计模式,饿汉式,低效 //object Student12 { // private val student: Student12 = new Student12("alice", 18) // // def getInstance():Student12={ // student // } //} // 定义伴生对象 // 单例设计模式,懒汉式,高效,不存在时,创建,对象存在时,不创建, object Student12 { private var student: Student12 = _ def getInstance(): Student12 = { if (student == null) { // 如果没有对象实例,则创建一个 student = new Student12("alice", 18) } student } }
-
特质(trait)
-
特质
package chapter06 object Test13_Trait { def main(args: Array[String]): Unit = { val student = new Student13() student.sayHello() student.dating() student.study() student.play() /** * hello from student * hello from student student * student student is dating * student student is study * young people student is playing */ } } // 定义一个父类 class Person13 { val name: String = "person" var age: Int = 18 def sayHello(): Unit = { println("hello from " + name) } } // 定义一个特质 trait Young { // 声明抽象和非抽象属性 var age: Int val name: String = "young" // 声明抽象和非抽象方法 def play(): Unit = { println(s"young people ${name} is playing") } def dating(): Unit } class Student13 extends Person13 with Young { // 重写冲突的属性 override val name = "student" // 实现抽象方法 override def dating(): Unit = { println(s"student ${name} is dating") } // 定义具体方法 def study(): Unit = println(s"student ${name} is study") override def sayHello(): Unit = { // 就近原则 super.sayHello() println(s"hello from student ${name}") } }
-
特质的混入
package chapter06 object Test14_TraitMixin { def main(args: Array[String]): Unit = { val student = new Student14 /** * student student is study * student student konwledge is increase 1 */ student.study() student.increase() /** * young people student is playing * student student konwledge is increase 2 */ student.play() student.increase() /** * student student is dating * student student konwledge is increase 3 */ student.dating() student.increase() } } // 再定义一个特质 trait Knowledge { var amount: Int = 0 def increase(): Unit } class Student14 extends Person13 with Young with Knowledge { // 重写冲突的属性 override val name = "student" // 实现抽象方法 override def dating(): Unit = { println(s"student ${name} is dating") } // 定义具体方法 def study(): Unit = println(s"student ${name} is study") override def sayHello(): Unit = { // 就近原则 super.sayHello() println(s"hello from student ${name}") } // 实现特质中的抽象方法 override def increase(): Unit = { amount += 1 println(s"student ${name} konwledge is increase ${amount}") } }
-
特质的叠加+钻石问题,从右到左叠加
package chapter06 object Test15_TraitOverlying { def main(args: Array[String]): Unit = { val student = new Student15 /** * konwledge increased */ student.increase() //钻石问题特征叠加 /** * my ball is a red-foot-ball */ val myFootBall = new MyFootBall println(myFootBall.describe()) } } // 再定义一个特质 trait Knowledge15 { var amount: Int = 0 def increase(): Unit = { println(s"konwledge increased") } } // 再定义一个特质 trait Talent15 { def singing(): Unit def dancing(): Unit def increase(): Unit = { println(s"talent increased") } } // 首先调用最后一个特质的方法 class Student15 extends Person13 with Talent15 with Knowledge15 { override def singing(): Unit = { println("student is singing") } override def dancing(): Unit = { println("student is dancing") } override def increase(): Unit = super.increase() } // 定义一个球类 trait Ball { def describe(): String = { "ball" } } // 定义颜色特征 trait ColorBall extends Ball { val color: String = "red" override def describe(): String = { color + "-" + super.describe() } } // 定义种类特征 trait CategoryBall extends Ball { val category: String = "foot" override def describe(): String = { category + "-" + super.describe() } } // 定义一个自定义球类 class MyFootBall extends CategoryBall with ColorBall { override def describe(): String = "my ball is a " + super.describe() }
-
钻石问题的特质叠加
-
特质和抽象类的区别
-
类型转换和转换
package chapter06 object Test17_Extends { def main(args: Array[String]): Unit = { //1. 类型的转化和检测 val student = new Student17("alice", 18) /** * hi from student alice * student alice is study */ student.sayHi() student.study() /** * hi from student alice */ val person: Person17 = new Student17("alice", 18) person.sayHi() /** * 类型判断 * student is Student17: true * student is Person17: true * person is Person17: true * person is Student17: true */ println("student is Student17: " + student.isInstanceOf[Student17]) println("student is Person17: " + student.isInstanceOf[Person17]) println("person is Person17: " + person.isInstanceOf[Person17]) // 体现多态 println("person is Student17: " + person.isInstanceOf[Student17]) val person2: Person17 = new Person17("alice", 18) /** * person is Person17: true * person is Student17: false */ println("person is Person17: " + person2.isInstanceOf[Person17]) println("person is Student17: " + person2.isInstanceOf[Student17]) // 类型转换 if (person.isInstanceOf[Student17]) { val newStudent: Student17 = person.asInstanceOf[Student17] newStudent.study() } println(classOf[Student17]) } } class Person17(val name: String, val age: Int) { def sayHi(): Unit = { println(s"hi from person $name") } } class Student17(name: String, age: Int) extends Person17(name = name, age = age) { override def sayHi(): Unit = { println(s"hi from student $name") } def study(): Unit = { println(s"student $name is study") } }