文章目录
面向对象编程(中级部分)
1. 包
1.1 Scala 包的特点概述
-
区分相同名字的类。
-
当类很多时,可以很好的管理类。
-
控制访问范围。
-
可以对类的功能进行扩展。
-
Scala
中包名和源码所在的系统文件目录结构可以不一致,但是编译后的字节码文件路径和包名会保持一致。
1.2 Scala 自动引入的常用包
java.lang.*
scala
包Predef
包
1.3 Scala 包注意事项和使用细节
scala
进行package
打包时,可以有以下形式:package com.guli{}
。scala
支持在一个文件中,可以同时创建多个包,以及给各个包创建class
,trait
,object
。- 包也可以嵌套使用(包中有包)。
- 作用域原则:可以直接向上访问。即:
Scala
中子包可以直接访问父包中的内容,大括号体现作用域。在子包和父包的类重名时,默认采取就近原则,如果希望指定使用某个类,则带上包名即可。 - 父包要访问子包的内容时,需要
import
对应的类。 - 可以在同一个
.scala
文件中,声明多个并列的package
。 - 包名可以相对也可以绝对,在一般情况下:我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理 。
1.4 包对象
-
包可以包含
class
,trait
,object
,但不能包含函数/方法或变量的定义,为弥补这一点的不足,scala
提供了包对象的概念来解决这个问题。 -
基本语法
package com.guli { package object scala { // com.guli.scala 的包对象 ... } package scala { // com.guli.scala 包 ... } }
- 每一个包都可以有包对象。
- 包对象的名字要和包名一致。
- 在包对象中可以定义变量,方法。
- 在包对象中定义的变量、方法,就可以在对应的包中使用。
- 在底层这个包对象会生成两个类
package.class
和package$.class
。
2. 包的可见性问题
-
当属性访问权限为默认时,从底层看属性是
private
的,但是因为提供了xxx_$eq
和xxx
方法,因此从使用效果看是任何地方都可以访问。 -
当方法访问权限为默认时,默认为
public
访问权限。 -
private
为私有权限,只在类的内部和伴生对象中可用。 -
protected
为受保护权限,scala
中受保护权限比Java
中更严格,只能子类访问,同包无法访问。 -
在
scala
中没有public
关键字,即不能用public
显式的修饰属性和方法。 -
包访问权限(表示属性有了限制。同时包也有了限制),这点和
Java
不一样,体现出Scala
包使用的灵活性。package com.guli.scala class Person { private[scala] val pname = "hello" // 增加包访问权限后,private同时起作用:不仅同类可以使 // 用,同时com.guli.scala包下的其他类也可以使用。 }
3. 包的引入
-
在
Scala
中,import
语句可以出现在任何地方,并不仅限于文件顶部,import
语句的作用一直延伸到包含该语句的块末尾。好处是:在需要时再引入包,缩小import
包的作用范围,提高效率。 -
Java
中如果想要导入包中所有的类,可以通过通配符*
,Scala
中采用_
。 -
如果不想要某个包中全部的类,而是其中的几个类,可以采用选取器
{}
。如:
import scala.collection.mutable.{HashMap,HashSet}
。 -
如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分,这个就是重命名。
如:
import java.util.{HashMap => JavaHashMap}
-
如果某个冲突的类根本就不会用到,那么这个类可以直接隐藏掉。
如:
import java.util.{ HashMap=>_, _}
,含义为引入java.util
包的所有类,但是忽略HahsMap
类。
4. 封装
Scala
中为了简化代码的开发,当声明属性为var
时,本身就自动提供了对应的setter/getter
方法。如果声明为private
的,那么自动生成的setter/getter
方法也是private
的;如果属性省略访问权限修饰符,那么自动生成的setter/getter
方法是public
的。
5. 继承
5.1 基本语法
class 子类名 extends 父类名 {
类体
}
5.2 重写方法
-
scala
规定:重写一个非抽象方法需要用override
修饰符,调用超类的方法使用super
关键字。class Person { def sayHi() { println("Person Hi") } } class student extends Person { override def sayHi() { // 重写父类的方法sayHi() super.sayHi() // 调用父类方法 println("student Hi") } }
5.3 Scala 中类型检查和转换
- 要测试某个对象是否属于某个给定的类,可以用
isInstanceOf[]
方法。 - 使用
asInstanceOf[]
方法将引用转换为子类的引用。 - 使用
classOf[]
获取对象的类名。
5.4 Scala 中超类的构造
-
类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用)。
-
只有主构造器可以调用父类的构造器。辅助构造器不能直接调用父类的构造器。在
Scala
的构造器中,不能使用super(params)
来调用父类构造器。而是使用:class Person(name: String) { // 父类的构造器 } class Emp(name: String) extends Person(name){ // 将子类参数传递给父类构造器 }
5.5 覆写字段
- 在
Scala
中,子类改写父类的字段,称之为覆写/重写字段。覆写字段需要使用override
修饰。 - 在
Java
中,只有方法的重写,没有属性的重写。 def
只能重写另一个def
(即:方法只能重写另一个方法)。val
只能重写另一个val
属性,或者,重写不带参数的def
。var
只能重写另一个抽象的var
属性。- 抽象的字段就是没有初始化的字段。
- 当一个类含有抽象的属性时,则该类需要标记为
abstract
。 - 对于抽象的属性,在底层不会生成对应的属性声明,而是生成两个对应的抽象方法:
xxx xxx_$eq
。 - 如果是覆写一个父类的抽象属性,那么
override
关键字可省略。
5.6 抽象类
- 在
Scala
中,通过abstract
关键字标记不能被实例化的类。方法不用标记abstract
,只要省掉方法体即可。抽象类可以拥有抽象字段,抽象字段就是没有初始值的字段。 - 抽象类不一定要包含
abstract
方法。也就是说,抽象类可以没有abstract
方法。 - 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为
abstract
。 - 抽象方法不能有主体,不允许使用
abstract
修饰。 - 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法和抽象属性,除非它自己也声明为
abstract
类。 - 抽象方法和抽象属性不能使用
private
、final
来修饰,因为这些关键字都是和重写/实现相违背的。 - 抽象类中可以有实现的方法。
- 子类重写抽象方法不需要
override
。
5.7 匿名子类
- 和
Java
一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。