经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Scala » 查看文章
7. Scala面向对象编程(中级部分)
来源:cnblogs  作者:铖歌  时间:2019/5/5 9:01:01  对本文有异议

7.1 包 

  7.1.1 看一个应用场景 

      现在有两个程序员共同开发一个项目,程序员xiaoming希望定义一个类取名Dog,程序员xiaohong也想定一个类也叫Dog,两个程序员还为此吵了起来,该怎么办?

      --->使用包即可解决这个问题

  7.1.2 回顾-Java包的三大作用 

      1) 区分相同名字的类

      2) 当类很多时,可以很好的管理类

      3) 控制访问范围

  7.1.3 回顾-Java打包命令 

      -打包基本语法

        package com.c;

      -打包的本质分析

        实际上就是创建不同的文件夹来保存类文件

  7.1.4 快速入门 

      使用打包技术来解决上面的问题,不同包下Dog类

  1. public class TestTiger {
  2. public static void main(String[] args) {
  3. //使用xm的Tiger
  4. com.c.scala_exercise.javapackage.xm.Tiger tiger01 = new com.c.scala_exercise.javapackage.xm.Tiger();
  5. //使用xh的Tiger
  6. com.c.scala_exercise.javapackage.xh.Tiger tiger02 = new com.c.scala_exercise.javapackage.xh.Tiger();
  7.  
  8. System.out.println("tiger01=" + tiger01 + "tiger02=" + tiger02);
  9. }
  10. }

  7.1.5 Scala包的基本介绍 

      和Java一样,Scala中管理项目可以使用包,但Scala中的包的功能更加强大,使用也相对复杂些

  7.1.6 Scala包快速入门 

      使用打包技术来解决上面的问题,不同包下Dog类

  1. object boke_demo01 {
  2. def main(args: Array[String]): Unit = {
  3. //使用xh的Tiger
  4. val tiger1 = new com.c.scala_exercise.scalapackage.xh.Tiger
  5. //使用xm的Tiger
  6. val tiger2 = new com.c.scala_exercise.scalapackage.xm.Tiger
  7.  
  8. println(tiger1 + " " + tiger2)
  9.  
  10. }
  11. }

  7.1.7 Scala包的特点概述 

      -基本语法

        package 包名

      -Scala包的作用(和Java一样)

        1) 区分相同名字的类

        2) 当类很多时,可以很好的管理类

        3) 控制访问范围

        4) 可以对类的功能进行扩展

      -Scala中包名和源码所在的系统文件目录结构可以不一致,但是编译后的字节码文件路径和包名会保持一致(这个工作由编译器完成)

  1. object boke_demo01 {
  2. def main(args: Array[String]): Unit = {
  3. //使用xh的Tiger
  4. val tiger1 = new com.c.scala_exercise.scalapackage.xh.Tiger
  5. //使用xm的Tiger
  6. val tiger2 = new com.c.scala_exercise.scalapackage.xm.Tiger
  7.  
  8. println(tiger1 + " " + tiger2)
  9.  
  10. }
  11. }
  12.  
  13. class Employee {
  14.  
  15. }

  7.1.8 包的命名 

      -命名规则:

        只能包含数字、字母、下划线、小圆点.,但是不能用梳子开头,也不要使用关键字

        demo.class.exercise  //错误,因为class是关键字

        demo.12a  //错误,因为不能以梳子开头

      -命名规范:

        一般是小写字母+小圆点一般是

        com.公司名.项目名.业务模块名 比如:com.baidu.io.model  com.baidu.io.controller

  7.1.9 Scala包注意事项和使用细节 

      1) Scala进行package打包时,可以有如下形式

  1. //代码说明
  2. //1. package com.boke{} 表示我们创建了包 com.boke ,在{}中
  3. // 我们可以继续写它的子包 scala //com.boke.scala, 还可以写类,特质trait,还可以写object
  4. //2. 即Sacla支持,在一个文件中,可以同时创建多个包,以及给各个包创建类,trait和object
  5. package com.boke { //包 com.boke
  6.  
  7. // class User { // 在com.boke包下创建个 User类
  8. // def sayHello(): Unit = {
  9. // //想使用 com.boke.scala2包下的 Monster
  10. // import com.boke.scala2.Monster
  11. // val monster = new Monster()
  12. // }
  13. // }
  14. //
  15. // package scala2 { // 创建包 com.boke.scala2
  16. // class User { // 在com.boke.scala2 包下创建个 User类
  17. // }
  18. //
  19. // class Monster { //
  20. //
  21. // }
  22. //
  23. // }
  24.  
  25.  
  26. //
  27. //说明
  28. //1. 在包中直接写方法,或者定义变量,就错误==>使用包对象的技术来解决
  29. //2. package object scala表示创建一个包对象scala, 它是com.boke.scala这个包对应的包对象
  30. //3. 每一个包都可以有一个包对象
  31. //4. 包对象的名字需要和子包一样
  32. //5. 在包对象中可以定义变量,方法
  33. //6. 在包对象中定义的变量和方法,就可以在对应的包中使用
  34. //7. 在底层这个包对象会生成两个类 package.class 和 package$.class
  35. package object scala {
  36. var name = "king"
  37.  
  38. def sayHiv(): Unit = {
  39. println("package object scala sayHI~")
  40. }
  41. }
  42.  
  43.  
  44. package scala { //包 com.boke.scala
  45.  
  46. class Person { // 表示在 com.boke.scala下创建类 Person
  47. val name = "Nick"
  48.  
  49. def play(message: String): Unit = {
  50. println(this.name + " " + message)
  51. }
  52. }
  53.  
  54. class User {
  55. def testUser(): Unit = {
  56. println("name = " + name)
  57. sayHiv()
  58. }
  59. }
  60.  
  61. object Test1 { //表示在 com.boke.scala 创建object Test1
  62. def main(args: Array[String]): Unit = {
  63.  
  64. println("name=" + name)
  65. name = "yy"
  66. sayHiv()
  67.  
  68. // println("ok")
  69. // //我们可以直接使用父包的内容
  70. // //1.如果有同名的类,则采用就近原则来使用内容(比如包)
  71. // //2.如果就是要使用父包的类,则指定路径即可
  72. // val user = new User
  73. // println("user=" + user) //
  74. // val user2 = new com.boke.User()
  75. // println("user2" + user2)
  76.  
  77. }
  78. }
  79.  
  80. }
  81.  
  82. }

      2) 包也可以像嵌套类那样嵌套使用(包中有包),好处:可以在同一个文件中,将类(class/object)、trait创建在不同的包中,这样就非常灵活了

      3) 作用域原则:可以直接向上访问。即Scala中子包中直接访问父包的内容,大括号体现作用域。(提示:Java中子包使用父包的类,需要import)。在子包和父包类重名时,默认采用就近原则,如果希望指定使用某个类,则带上包名即可

      4) 父包要访问子包的内容时,需要import对应的类等

      5) 可以在同一个.scala文件中声明多个并列的package(建议嵌套的package不要超过3层)

      6) 包名可以相对也可以绝对,比如访问 BeanProperty 的绝对路径是: _root_.scala.beans.BeanProperty,在一般情况下,我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理

  1. import scala.beans.BeanProperty
  2.  
  3. class Manager(var name: String) {
  4. //第一种形式 [使用相对路径引入包]
  5. @BeanProperty var age: Int = _
  6. //第二种形式, 和第一种一样,都是相对路径引入
  7. @scala.beans.BeanProperty var age2: Int = _
  8. //第三种形式, 是绝对路径引入,可以解决包名冲突
  9. @_root_.scala.beans.BeanProperty var age3: Int = _
  10. }
  11.  
  12. object TestBean {
  13. def main(args: Array[String]): Unit = {
  14. val m = new Manager("jack")
  15. println("m=" + m)
  16. }
  17. }

  7.1.10 包对象 

      基本介绍:包可以包含类、对象和特质(trait),但不能包含函数/方法或变量的定义。这是Java虚拟机的局限。为了弥补这一点,Scala提供了包对象的概念来解决这个问题

  7.1.11 包对象的应用案例

  1. /说明
  2. //1. 在包中直接写方法,或者定义变量,就错误==>使用包对象的技术来解决
  3. //2. package object scala表示创建一个包对象scala, 它是com.boke.scala这个包对应的包对象
  4. //3. 每一个包都可以有一个包对象
  5. //4. 包对象的名字需要和子包一样
  6. //5. 在包对象中可以定义变量,方法
  7. //6. 在包对象中定义的变量和方法,就可以在对应的包中使用
  8. //7. 在底层这个包对象会生成两个类 package.class 和 package$.class
  9. package object scala {
  10. var name = "king"
  11.  
  12. def sayHiv(): Unit = {
  13. println("package object scala sayHI~")
  14. }
  15. }
  16.  
  17.  
  18. package scala { //包 com.boke.scala
  19.  
  20. class Person { // 表示在 com.boke.scala下创建类 Person
  21. val name = "Nick"
  22.  
  23. def play(message: String): Unit = {
  24. println(this.name + " " + message)
  25. }
  26. }
  27.  
  28. class User {
  29. def testUser(): Unit = {
  30. println("name = " + name)
  31. sayHiv()
  32. }
  33. }
  34.  
  35. object Test1 { //表示在 com.boke.scala 创建object Test1
  36. def main(args: Array[String]): Unit = {
  37.  
  38. println("name=" + name)
  39. name = "yy"
  40. sayHiv()
  41.  
  42. }
  43. }
  44.  
  45. }

  7.1.12 包对象的底层的实现机制 

 如图所示:一个包对象会生成两个类package和package$

如图所示:说明了包去使用包对象的变量或者方法的原理

  7.1.13 包对象的注意事项 

      1) 每个包都可以有一个包对象,需要在父包中定义它

      2) 包对象名称需要和包名一致,一般用来对包的功能补充

7.2 包的可见性问题 

  7.2.1 回顾-Java访问修饰符基本介绍 

      Java提供四种访问控制修饰符号来控制方法和变量的访问权限(范围)

        1) 公开级别:用public修饰,对外公开

        2) 受保护级别:用protected修饰,对于子类和同一包中的类公开

        3) 默认级别:没有修饰符,向同一个包中的类公开

        4) 私有级别:用private修饰,只有类本身可以访问,不对外公开

  7.2.2 回顾-Java中4中访问修饰符的访问范围 

  7.2.3 回顾-Java访问修饰符使用注意事项 

      1) 修饰符可以用来修饰类中的属性,成员方法以及类

      2) 只有默认的和public才能修饰类!并且遵循上述访问权限的特点

  7.2.4 Scala中包的可见性介绍 

      在Java中,访问权限分为:public,private,protected和默认。在Scala中,可以通过类似的修饰符达到同样的效果,但是使用上有所区别

      案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val c = new Clerk()
  5. c.showInfo()
  6. Clerk.test(c)
  7.  
  8. }
  9. }
  10.  
  11. //类
  12. class Clerk {
  13. var name: String = "jack" //
  14. private var sal: Double = 9999.9
  15. protected var age = 23
  16. var job: String = "大数据工程师"
  17.  
  18. def showInfo(): Unit = {
  19. //在本类可以使用私有的
  20. println(" name " + name + " sal= " + sal)
  21. }
  22. }
  23.  
  24. object Clerk {
  25. def test(c: Clerk): Unit = {
  26. //这里体现出在伴生对象中,可以访问c.sal
  27. println("test() name=" + c.name + " sal= " + c.sal)
  28. }
  29. }

  7.2.5 Scala中包的可见性和访问修饰符的使用 

      1) 当属性访问权限为默认时,从底层看属性是private的,但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter]方法,因此从使用效果看是任何地方都可以访问

      2) 当方法访问权限为默认时,默认为public访问权限

      3) private为私有权限,只有在类的内部和伴生对象中可用

      4) protected为受保护权限,Scala中受保护权限比Java中更为严格,只能子类访问,同包无法访问

      5) 在Scala中没有public关键字,即不能用public显示的修饰属性和方法

      6) 包访问权限(表示属性有了限制,同时包也有了限制),这点和Java不一样,体现出Scala包的灵活性

  1. package com.scala.exercise
  2.  
  3. class Person {
  4.  
  5. //增加包访问权限后
  6. //1.private同时起作用,不仅同类可以使用
  7. //2.com.scala.exercise中包下的其它类也可以使用
  8. private[exercise] val name = "Jack"
  9. //当然,也可以将可见度延展到上层包
  10. private[scala] val age = 23
  11. //说明:private可以变化,比如protected[scala],非常的灵活
  12. }

      7) 整体的案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val c = new Clerk()
  5. c.showInfo()
  6. Clerk.test(c)
  7.  
  8. }
  9. }
  10.  
  11. //类
  12. class Clerk {
  13. var name: String = "jack" //
  14. private var sal: Double = 9999.9
  15. protected var age = 23
  16. var job: String = "大数据工程师"
  17.  
  18. def showInfo(): Unit = {
  19. //在本类可以使用私有的
  20. println(" name " + name + " sal= " + sal)
  21. }
  22. }
  23.  
  24. //当一个文件中出现了 class Clerk 和 object Clerk
  25. //1. class Clerk 称为伴生类
  26. //2. object Clerk 的伴生对象
  27. //3. 因为Scala设计者将static拿掉, 他就是设计了 伴生类和伴生对象的概念
  28. //4. 伴生类 写非静态的内容 伴生对象 就是静态内容
  29. //5.
  30. object Clerk {
  31. def test(c: Clerk): Unit = {
  32. //这里体现出在伴生对象中,可以访问c.sal
  33. println("test() name=" + c.name + " sal= " + c.sal)
  34. }
  35. }
  36.  
  37. class Person {
  38. //这里我们增加一个包访问权限
  39. //下面private[scala] : 1,仍然是private 2. 在scala包(包括子包)下也可以使用name ,相当于扩大访问范围
  40.  
  41. protected[scala] val name = "Jack"
  42. }

7.3 包的引入 

  7.3.1 Scala引入包基本介绍 

      Scala引入包也是使用import,基本的原理跟机制和Java一样,但是Scala中的import功能更佳强大,也更灵活。因为Scala语言源自Java,所以java.lang包中的类会自动引入到当前环境中,而Scala中的scala包和predef包的类也会自动引入到当前环境中,即起其下的类可以直接使用。如果想要把其它包中的类引入到当前环境中,需要使用import

  7.3.2 Scala引入包的细节和注意事项 

      1) 在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部,import语句的作用一直延伸到包含该语句的块末尾。这种语法的好处是:在需要时引入包,缩小import包的作用范围,提高效率

  1. class User {
  2. import scala.beans.BeanProperty
  3. @BeanProperty var name : String = ""
  4. }
  5.  
  6. class Dog {
  7. @BeanProperty var name : String = "" //可以吗? No
  8. }

      2) Java中如果想要导入包中所有的类,可以通过通配符*,Scala中采用_(下划线)

      3) 如果不想要某个包中全部的类,而是其中几个类,可以采用选取器(大括号)

  1. def test(): Unit = {
  2. //可以使用选择器,选择引入包的内容,这里,我们只引入 HashMap, HashSet
  3. import scala.collection.mutable.{HashMap, HashSet}
  4. var map = new HashMap()
  5. var set = new HashSet()
  6. }

      4) 如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分,这个就是重命名

  1. def test2(): Unit = {
  2. //下面的含义是 将 java.util.HashMap 重命名为 JavaHashMap
  3. import java.util.{HashMap => JavaHashMap}
  4. import scala.collection.mutable._
  5. var map = new HashMap() // 此时的 HashMap 指向的是 scala 中的 HashMap
  6. var map1 = new JavaHashMap(); // 此时使用的 java 中 hashMap 的别名
  7.  
  8. }

      5) 如果某个冲突的类根本就不会用到,那么这个类可以直接隐藏掉

  1. import java.util.{ HashMap=>_, _} // 含义为 引入 java.util 包的所有类,但是忽略 HahsMap 类.
  2. var map = new HashMap()

7.4 面向对象编程方法-抽象 

      -如何理解抽象

        我们在前面去定义一个类的时候,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象

                        

7.5 面向对象编程三大特征 

  7.5.1 基本介绍 

      面向对象有三大特征:封装、继承、多态

  7.5.2 封装介绍 

      封装(encapsulation)就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员变量),才能对数据进行操作

  7.5.3 封装的理解和好处 

      1) 隐藏实现细节

      2) 可以对数据进行验证,保证安全合理

      3) 同时可以加入业务逻辑

  7.5.4 如何体现封装 

      1) 对类中的属性进行封装

      2) 通过成员方法,包实现封装

  7.5.5 封装的实现步骤 

      1) 将属性进行私有化

      2) 提供一个公共的set方法,用于对属性判断并赋值

  1. def setXxx(参数名 : 类型) : Unit = {
  2. //加入数据验证的业务逻辑
  3. 属性 = 参数名
  4. }

      3) 提供一个公共的get方法,用于获取属性的值

  1. def getXxx() [: 返回类型] = {
  2. return 属性
  3. }

  7.5.6 Scala封装的注意事项的小结 

      1) Scala中为了简化代码的开发,当声明属性var时,本身就自动提供了对应setter/getter方法,如果属性声明为private的,那么自动生成的setter/getter方法也是private的,如果属性省略访问权限修饰符,那么自动生成的setter/getter方法时public的

      2) 因此我们如果只是对一个属性进行简单的set和get,只要声明一下该属性(属性使用默认访问修饰符),不用写专门的set和get,默认会创建,访问时,直接对象.变量。这样也是为了保持访问一致性

      3) 从形式上看 dog.food 直接访问属性,其实底层仍然是访问的方法,看一下反编译的代码就会明白

      4) 有了上面的特性,目前很多新的框架,在进行反射时,也支持对属性的直接反射

7.6 面向对象编程-继承 

  7.6.1 Java继承的简单回顾

  1. class 子类名 extends 父类名 { 类体 }

  7.6.2 继承基本介绍和示意图 

      继承可以解决代码复用,让我们的编程更佳靠近人类的思维,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(比如Student),在父类中定义这些相同的属性和方法,所有的子类不需要重复定义这些属性和方法,只需要通过extends语句来声明继承父类即可。和Java一样,Scala也支持类的单继承

  7.6.3 Scala继承的基本语法 

  1. class 子类名 extends 父类名 { 类体 }

  7.6.4 Scala继承快速入门 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. //使用
  5. val student = new Student
  6. student.name = "jack" //调用了student.name()
  7. student.studying()
  8. student.showInfo()
  9. }
  10. }
  11.  
  12. class Person { //Person类
  13. var name: String = _
  14. var age: Int = _
  15.  
  16. def showInfo(): Unit = {
  17. println("学生信息如下:")
  18. println("名字:" + this.name)
  19. }
  20. }
  21.  
  22. //Student类继承Person
  23. class Student extends Person {
  24. def studying(): Unit = {
  25. //这里可以使用父类的属性
  26. println(this.name + "学习 scala中....")
  27. }
  28. }

  7.6.5 Scala继承给编程带来的便利 

      1) 代码的复用性提高了

      2) 代码的扩展性和维护性提高了

  7.6.6 Scala子类继承了什么,怎么继承了 

      子类继承了所有的属性,只是私有的属性不能直接访问,需要通过公共的方法去访问[debug代码验证可以看到]

  1. //说明
  2. //1. 在scala中,子类继承了父类的所有属性
  3. //2. 但是private的属性和方法无法访问
  4.  
  5. object boke_demo01 {
  6.  
  7. def main(args: Array[String]): Unit = {
  8. val sub = new Sub()
  9. sub.sayOk()
  10. //sub.test200() //编译器不让过.
  11. }
  12. }
  13.  
  14. //父类(基类)
  15. class Base {
  16. var n1: Int = 1 //public n1() , public n1_$eq()
  17. protected var n2: Int = 2
  18. private var n3: Int = 3 // private n3() , private n3_$eq()
  19.  
  20. def test100(): Unit = { // 默认 public test100()
  21. println("base 100")
  22. }
  23.  
  24. protected def test200(): Unit = { // public
  25. println("base 200")
  26. }
  27.  
  28. private def test300(): Unit = { //private
  29. println("base 300")
  30. }
  31.  
  32. //编译原理->业务逻辑->性能优化
  33. }
  34.  
  35. //Sub 继承 Base
  36. class Sub extends Base {
  37.  
  38. def sayOk(): Unit = {
  39. this.n1 = 20 //这里访问本质this.n1_$eq()
  40. this.n2 = 40
  41.  
  42. println("范围" + this.n1 + this.n2)
  43.  
  44. test100() //
  45. test200() //在子类中使用protected
  46. }
  47. }

 

  7.6.7 Scala重写方法 

      说明:Scala明确规定,重写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val emp = new Emp
  5. emp.printName()
  6. }
  7. }
  8.  
  9. //Person类
  10. class Person {
  11. var name: String = "tom"
  12.  
  13. def printName() { //输出名字
  14. println("Person printName() " + name)
  15. }
  16.  
  17. def sayHi(): Unit = {
  18. println("sayHi...")
  19. }
  20. }
  21.  
  22. //这里我们继承Person
  23. class Emp extends Person {
  24. //这里需要显式的使用override
  25. override def printName() {
  26. println("Emp printName() " + name)
  27. //在子类中需要去调用父类的方法,使用super
  28. super.printName()
  29. sayHi()
  30. }
  31. }

  7.6.8 Scala中类型检查和转换 

      -基本介绍

        要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。用asInstanceOf方法将引用转换为子类的引用。classOf获取对象名

        classOf[String]就如同Java的String.class

        obj.isInstanceOf[T]就如同Java的 obj instanceofT 判断obj是不是T类型

        obj.asInstanceOf[T] 就如同Java的(T)obj 将obj强转成T类型

      -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. //ClassOf的使用,可以得到类名
  6. println(classOf[String]) // 输出
  7. val s = "king"
  8. println(s.getClass.getName) //使用反射机制
  9.  
  10. //isInstanceOf asInstanceOf
  11. var p1 = new Person
  12. var emp = new Emp
  13. //将子类引用给父类(向上转型,自动)
  14. p1 = emp
  15. //将父类的引用重新转成子类引用(多态),即向下转型
  16. var emp2 = p1.asInstanceOf[Emp]
  17. emp2.sayHello()
  18.  
  19. }
  20. }
  21.  
  22. //Person类
  23. class Person {
  24. var name: String = "tom"
  25.  
  26. def printName() { //输出名字
  27. println("Person printName() " + name)
  28. }
  29.  
  30. def sayHi(): Unit = {
  31. println("sayHi...")
  32. }
  33. }
  34.  
  35. //这里我们继承Person
  36. class Emp extends Person {
  37. //这里需要显式的使用override
  38. override def printName() {
  39. println("Emp printName() " + name)
  40. //在子类中需要去调用父类的方法,使用super
  41. super.printName()
  42. sayHi()
  43. }
  44.  
  45. def sayHello(): Unit = {
  46.  
  47. }
  48. }

      -最佳实践

        类型检查和转换的最大价值在于:可以判断传入对象的类型,然后转成对应的子类对象,进行相关操作,这里也体现出多态的特点

  7.6.9 Java中超类的构造  

      说明:从代码可以看出,在Java中,创建子类对象时,子类的构造器总是去调用一个父类的构造器(显示或者隐式调用)

  1. public class JavaBaseConstractor {
  2.  
  3. public static void main(String[] args) {
  4.  
  5. //1.A()
  6. //2.B()
  7. B b = new B();
  8.  
  9. //1.A(String name) jack
  10. //2.B(String name) jack
  11. B b2 = new B("jack");
  12.  
  13. }
  14. }
  15.  
  16. class A {
  17. public A() {
  18. System.out.println("A()");
  19. }
  20.  
  21. public A(String name) {
  22. System.out.println("A(String name)" + name);
  23. }
  24. }
  25.  
  26. class B extends A {
  27. public B() {
  28. //这里会隐式调用super(); 就是无参的父类构造器A()
  29. //super();
  30. System.out.println("B()");
  31. }
  32.  
  33. public B(String name) {
  34. super(name);
  35. System.out.println("B(String name)" + name);
  36. }
  37. }

  7.6.10 Scala中超类的构造 

      1) 类有一个主构造器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用)

      2) 只有主构造器可以调用父类的构造器,辅助构造器不能直接调用父类的构造器,在Scala的构造器中,不能调用super(params)

      

      3) 案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. //分析执行的顺序
  6. //1.Person...
  7. //2.Emp ....
  8. //3.Emp 辅助构造器~
  9. val emp1 = new Emp("smith")
  10.  
  11. println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
  12. //Person..
  13. //Emp ....
  14. val emp2 = new Emp("terry", 10)
  15. emp2.showInfo() // 雇员的名字 terry
  16.  
  17. }
  18. }
  19.  
  20. //父类Person
  21. class Person(pName: String) {
  22. var name = pName
  23. println("Person...")
  24.  
  25. def this() {
  26. this("默认的名字")
  27. println("默认的名字")
  28.  
  29. }
  30. }
  31.  
  32. //子类Emp继承Person
  33. class Emp(eName: String, eAge: Int) extends Person(eName) {
  34.  
  35. println("Emp ....")
  36.  
  37. //辅助构造器
  38. def this(name: String) {
  39.  
  40. this(name, 100) // 必须调用主构造器
  41. this.name = name
  42. println("Emp 辅助构造器~")
  43. }
  44.  
  45. def showInfo(): Unit = {
  46. println("雇员的名字 ", name)
  47. }
  48. }

  7.6.11 覆写字段 

      -基本介绍

        在Scala中,子类改写父类的字段,我们称之为覆写/重写字段。覆写字段需要使用override修饰 

      -回顾

        在Java中只有方法的重写,没有属性/字段的重写,准确的讲,是隐藏字段代替了重写

      -回顾-Java另一重要特性:动态绑定机制

        动态绑定机制:

        1) 如果调用的是方法,则JVM机会将改方法和对象的内存地址绑定

        2) 如果调用的是一个属性,则没有动态绑定机制,在哪里调用就返回对应值

  1. public class JavaDaynamicBind {
  2. public static void main(String[] args) {
  3.  
  4. //将一个子类的对象地址,交给了一个AA(父类的)引用
  5. //java的动态绑定机制的小结
  6. //1.如果调用的是方法,则Jvm机会将该方法和对象的内存地址绑定
  7. //2.如果调用的是一个属性,则没有动态绑定机制,在哪里调用,就返回对应值
  8. AA obj = new BB();
  9. System.out.println(obj.sum()); // 30
  10. System.out.println(obj.sum1()); // 20
  11.  
  12. }
  13. }
  14.  
  15. class AA {
  16. public int i = 10;
  17.  
  18. public int sum() {
  19. return getI() + 10;
  20. }
  21.  
  22. public int sum1() {
  23. return i + 10;
  24. }
  25.  
  26. public int getI() {
  27. return i;
  28. }
  29. }
  30.  
  31. class BB extends AA {
  32. public int i = 20;
  33.  
  34. public int getI() {
  35. return i;
  36. }
  37.  
  38. }

       -Scala覆写字段快速入门

  1. object ScalaFiledOverride {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val obj1: AAA = new AAA
  5. val obj2: BBB = new BBB
  6. //obj1.age => obj1.age() //动态绑定机制
  7. //obj2.age => obj2.age()
  8. println("obj1.age=" + obj1.age + "\t obj2.age=" + obj2.age)
  9. }
  10. }
  11.  
  12. class AAA {
  13. val age: Int = 10 // 会生成 public age()
  14. }
  15.  
  16. class BBB extends AAA {
  17. override val age: Int = 20 // 会生成 public age()
  18. }

       反编译后的代码:

      -覆写字段的注意事项和细节

        1) def只能重写另一个def(即:方法只能重写另一个方法)

        2) val只能重写另一个val属性 或 重写不带参数的def

        -案例演示1(val只能重写另一个val属性)

  1. object ScalaFiledOverride {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val obj1: AAA = new AAA
  5. val obj2: BBB = new BBB
  6. //obj1.age => obj1.age() //动态绑定机制
  7. //obj2.age => obj2.age()
  8. println("obj1.age=" + obj1.age + "\t obj2.age=" + obj2.age)
  9. }
  10. }
  11.  
  12. //如果 val age 改成 var 报错
  13. class AAA {
  14. val age: Int = 10 // 会生成 public age()
  15. }
  16.  
  17. class BBB extends AAA {
  18. override val age: Int = 20 // 会生成 public age()
  19. }

      -案例演示2(重写不带参数的def)

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val b1 = new BB()
  5. println(b1.sal) // 0
  6. val b2: AA = new BB()
  7. println("b2.sal=" + b2.sal()) // 0
  8. }
  9. }
  10.  
  11. class AA {
  12. def sal(): Int = {
  13. return 10
  14. }
  15. }
  16.  
  17. class BB extends AA {
  18. override val sal: Int = 0 //底层 public sal
  19. }

        3) var只能重写另一个抽象的var属性

  1. object boke_demo01 {
  2. def main(args: Array[String]): Unit = {
  3. println("hello~")
  4. }
  5. }
  6.  
  7. //在AA中,有一个抽象的字段(属性)
  8. //1. 抽象的字段(属性):就是没有初始化的字段(属性)
  9. //2. 当一个类含有抽象属性时,则该类需要标记为abstract
  10. //3. 对于抽象的属性,在底层不会生成对应的属性声明,而是生成两个对应的抽象方法(name name_$eq)
  11. abstract class AA {
  12. var name: String //抽象
  13. var age: Int = 10
  14. }
  15.  
  16. class Sub_AA extends AA {
  17. //说明
  18. //1. 如果我们在子类中去重写父类的抽象属性,本质是实现了抽象方法
  19. //2. 因此这里我们可以写override ,也可以不写
  20. override var name: String = ""
  21.  
  22. }

      -抽象属性:声明未初始化的变量就是抽象的属性,抽象属性在抽象类中

      -var重写抽象的var属性小结

        1) 一个属性没有初始化,那么这个属性就是抽象属性

        2) 抽象属性在编译成字节码文件时,属性并不会声明,但是会自动生成抽象方法,所以类必须声明为抽象类

        3) 如果是覆写一个父类的抽象,那么override关键字可以省略[原因:父类的抽象属性,生成的是抽象方法,因此不涉及到方法重写的概念,override可以省略]

  7.6.12 抽象类 

      -基本介绍

        在Scala中,通过abstract关键字标记不能被实力化的类。方法不用标记abstract,只要省掉方法体即可,抽象类可以拥有抽象字段,抽象字段/属性就是没有初始值的字段

      -快速入门案例

        将Animal做成抽象类,包含一个抽象方法cry()

  1. object AbstractDemo01 {
  2. def main(args: Array[String]): Unit = {
  3. }
  4. }
  5.  
  6. //抽象类
  7. abstract class Animal {
  8. var name: String //抽象的字段
  9. var age: Int // 抽象的字段
  10. var color: String = "black" //普通属性
  11. def cry() //抽象方法,不需要标记 abstract
  12. }

  7.6.13 Scala抽象类使用的注意事项和细节 

      1) 抽象类不能被实例

  1. //默认情况下,一个抽象类是不能实例化的,但是你实例化时,动态的实现了抽象类的所有 //抽象方法,也可以,如下
  2. val animal = new Animal {
  3. override def sayHello (): Unit = {
  4. println ("say hello~~~~")
  5. }
  6. }
  7. animal.sayHello ()

      2) 抽象类不一定要包含abstract方法,也就是说,抽象类可以没有abstract方法

  1. abstract class Animal {
  2. //在抽象类中可以有实现的方法
  3. def sayHi (): Unit = {
  4. println("hello") }
  5. }

      3) 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为abstract

      4) 抽象方法不能有主体,不允许使用abstract修饰

      5) 如果一个类继承了抽象类,则它必须实现抽象类中所有的抽象方法和抽象属性,除非它自己也声明为abstract类

  1. abstract class Animal {
  2.  
  3. def sayHello()
  4. var food: String
  5. }
  6.  
  7. class Dog extends Animal {
  8.  
  9. override def sayHello(): Unit = {
  10. println("小狗汪汪叫!")
  11. }
  12.  
  13. override var food: String = _
  14. }

      6) 抽象方法和抽象属性不能使用private、final来修饰,因为这些关键字都是和重写/实现相违背的

      7) 抽象类中可以有实现的方法

      8) 子类重写抽象方法不需要override,写上也不会错

  7.6.14 匿名子类

      -基本介绍

        和Java一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类

      -回顾-Java中匿名子类的使用

  1. public class NoNameDemo01 {
  2. public static void main(String[] args) {
  3. //在java中去创建一个匿名子类对象
  4. A a = new A() {
  5. @Override
  6. public void cry() {
  7. System.out.println("cry...");
  8. }
  9. };
  10. a.cry();
  11. }
  12. }
  13.  
  14. abstract class A {
  15. abstract public void cry();
  16. }

      -Scala匿名子类的使用 

  1. object boke_demo01 {
  2. def main(args: Array[String]): Unit = {
  3. val monster = new Monster {
  4. override def cry(): Unit = {
  5. println("...:)")
  6. }
  7.  
  8. override var name: String = _
  9. }
  10. monster.cry()
  11. }
  12. }
  13.  
  14. abstract class Monster {
  15. var name: String
  16.  
  17. def cry()
  18. }

  7.6.15 继承层级 

      -Scala继承层级一览图

      -对上图的一个小结

        1) 在Scala中,所有其它类都是AnyRef的子类,类似Java的Obiect

        2) AnyVal和AnyRef都扩展自Any类,Any类是子节点

        3) Any中定义了isInstanceOf、asInstanceOf方法,以及哈希方法等

        4) Null类型的唯一实例就是null对象,可以将null赋值给任何引用,但不能赋值给值类型的变量

        5) Nothing类型没有实例,它对于泛型结构是有用处的,举例:空列表Nil的类型就是List[Nothing],它是List[T]的子类型,T可以是任何类

       

 

原文链接:http://www.cnblogs.com/zhanghuicheng/p/10788213.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号