scala 学习笔记
前言
一、包
Java 包的三大作用:
- 区分相同名字的类
- 当类很多时,可以很好的管理类
- 控制访问范围 实际上就是创建不同的文件夹来保存类文件,java中 包名和 源码所在的系统 文件目录结构要一致,最常见的操作就是导包,引用包下的某个类。
1.Scala 包的命名
命名规则: 只能包含 数字、字母、下划线、 小圆点.,但不能用数字开头, 也不要使用关键字。 一般是小写字母+小圆点一般是 com. 公司名. 项目名.
2.包对象
包可以包含 类、对象和特质trait,但 不能包含函数 数/ 方法或变量的定义。这是Java虚拟机的局限。为了弥补这一点不足,scala提供了包对象的概念来解决这个问题
- 每个包都可以有一个包对象
- 包对象名称需要和包名一致
- 一般用来对包的功能补充
package com.test{
//每个包都可以有一个包对象。你需要在父包(com.test)中定义它,且名称与子包一样。
package object scala {
var name = "jack"
def sayOk(): Unit = {
println("package object sayOk!")
}
}
package scala {
class Test {
def test() : Unit ={
//这里的name就是包对象scala中声明的name
println(name)
sayOk()//这个sayOk 就是包对象scala中声明的sayOk
}
}
object TestObj {
def main(args: Array[String]): Unit = {
val t = new Test()
t.test()
//因为TestObje和scala这个包对象在同一包,因此也可以使用
println("name=" + name)
}}}}
3.包的可见性
修饰符 java提供 四种访问控制修饰符号控制方法和变量的访问权限:
- 公开级别:用public 修饰,对外公开
- 受保护级别:用protected修饰,对子类和同一个包中的类公开
- 默认级别:没有修饰符号,向同一个包的类公开.
- 私有级别:用private修饰,只有类本身可以访问,不对外公开
- 修饰符可以用来修饰类中的 属性,成员方法以及 类
- 只有 默认的和public才能修饰类!,并且遵循上述访问权限的特点。
scala包的可见性和访问修饰符的使用
- 当属性访问权限为默认时,从底层看属性是private的,但是因为提供了 xxx_$eq()[类似setter]/xxx()[类似getter] 方法,因此从使用效果看是任何地方都可以访问)
- 当方法访问权限为默认时, 默认为public 访问权限
- private为私有权限,只在 类的内部和 伴生对象中可用
- protected 为受保护权限,scala中受保护权限比Java中更严格,只能子类访问,同包无法访问 (编译器)
- 在scala中没有public关键字,即 不能用public显式的修饰属性和方法 显式的修饰属性和方法。
- 包访问权限(表示属性有了限制。同时包也有了限制),较java灵活
class Person {
// 增加包访问权限后,1.private同时起作用。不仅同类可以使用
//2. 同时com.test.scala中包下其他类也可以使用
private [scala] val pname="hello"
}
4.包的引入
- 在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部,import语 句的作用一直延伸到包含该语句的块末尾。这种语法的好处是: 在需要时在引 入包,缩小import 包的作用范围,提高效率。
- Java中如果想要导入包中所有的类,可以通过通配符*,Scala中采用下 _
import java.io._
- 如果不想要某个包中全部的类,而是其中的几个类,可以采用 选取器(大括号)
import scala.io.{Source, StdIn}
- 如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分,这个就是重命名
//重命名
import java.util.{ HashMap=>JavaHashMap, List}
import scala.collection.mutable._
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap
var map1 = new JavaHashMap(); // 此时使用的java中hashMap的别名
- 如果某个冲突的类根本就不会用到,那么这个类可以直接 隐藏掉
// 含义为 引入java.util包的所有类,但是忽略HahsMap类
import java.util.{ HashMap=>_, _}
二、三大特征
1.封装
封装(encapsulation)就是把抽象出的 数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过 被授权的操作(成员方法),才能对数据进行操作。在java中一般通过java bean,把属性设置成private,然后对外提供getXXX/setxxx方法 scala特点:
- Scala 中为了简化代码的开发,当声明属性时,本身就自动提供了对应setter/getter方法,如果属性声明为private的,那么自动生成的setter/getter方法也是private的,如果属性省略访问权限修饰符,那么自动生成的setter/getter方法是public的
- 因此我们如果只是对一个属性进行简单的 set和 和get ,只要声明一下该属性( 属性使 用默认访问修饰符) 不用写专门的getset ,默认会创建, 访问时,直接对象. 变量。这样也是为了保持访问一致性
2.继承
继承可以 解决代码复用,让我们的编程更加靠近人类思维.当 多个类存在相同的属性(变量)和 方法时,可以从这些类中抽象出父类(比如Student),在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends语句来声明继承父类即可。
class 子类名 extends 父类名 { 类体 }
子类继承父类的属性和方法,只是私有的属性不能直接访问,需要 通过公共的方法去访问。 重写方法:scala明确规定,重写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字
只有主构造器可以调用父类的构造器。辅助构造器不能直接调用父类的构造器。在Scala的构造器中,你不能调用super(params)
class Person(name: String) { //父类的构造器
}
// 将子类参数传递给父类构造器, 这种写法√
class Emp (name: String) extends Person(name) {
// super(name) ( ×) 没有这种语法
def this() {
super("abc") // ( ×) 不能在辅助构造器中调用父类的构造器
}
}
覆盖字段
在Java中只有方法的重写,没有属性/字段的重写,准确的讲,是隐藏字段代替了重写。 在Scala中,子类改写父类的字段,我们称为 覆写/ 重写字段。覆写字段需使用override修饰。 覆写字段的注意事项和细节
- def只能重写另一个def(即:方法只能重写另一个方法)
- val只能重写另一个val 属性 或 重写不带参数的def
- var只能重写另一个 抽象的var 属性
抽象属性
抽象属性:声明未初始化的变量就是抽象的属性, 抽象属性在抽象类 var重写抽象的var属性小结
- 一个属性没有初始化,那么这个属性就是抽象属性
- 抽象属性在编译成字节码文件时,属性并不会声明,但是会自动生成抽象方法,所以 类必须声明为抽象类
- 如果是覆写一个父类的抽象属性,那么override 关键字可省略 [ 原因:父类的抽象属性, 生成的是抽象方法,因此就不涉及到方法重写的概念,因此override 可省略
- 在scala中通过abstract关键字abstract可以用于标记类,不能用于标记方法,只要省掉方法体即可
abstract class Person() { // 抽象类
var name: String // 抽象字段, 没有初始化
def printName // 抽象方法, 没有方法体
}
抽象类的价值更多是在于设计 ,是设计者设计好后, 让子类继承并实现抽象类
Scala抽象类使用的注意事项和细节讨论
- 抽象类不能被实例
- 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
- 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为abstract
- 抽象方法不能有主体,不允许使用abstract修饰。
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法和 抽象属性, 除非它自己也声明为abstract类。【 案例演示+反编译 】 ) 6) 抽象方法和抽象属性 不能使用private、final 来修饰,因为这些关键字都是和 重写/ / 实现相违背的。
- 抽象类中可以有实现的方法.
- 子类重写抽象方法不需要override,写上也不会错(可写可不写)
3.匿名子类
和JAVA一样可以 通过包含带有定义或重写的代码块的方式创建一个匿名的子类.
abstract class Monster{
//抽象属性
var name : String
//抽象方法
def cry()
}
//实际定义了一个匿名的Monster子类,重写了属性和方法,但是没具体名字
var monster = new Monster {
override var name: String = "牛魔王"
override def cry(): Unit = {
println("牛魔王哼哼叫唤..")
}
}
3.多态
object employee {
def main(args: Array[String]): Unit = {
val xiaowang = new ptemploy
xiaowang.name="小王"
xiaowang.pay=10000
println(xiaowang.getAnnual)
xiaowang.work()
println("------------")
val wangzong = new mgemployee
wangzong.name="王总"
wangzong.pay=50000
wangzong.bonus=100000
println(wangzong.getAnnual)
wangzong.manage()
}
//员工抽象类
abstract class employee{
var name: String
var pay:Double
def getAnnual:Double{}
}
//普通员工
class ptemploy extends employee{
override var name: String = _
override var pay: Double = _
var bonus:Double= _
override def getAnnual:Double =
{
pay*12
}
def work(): Unit ={
println(name+" is working")
}
}
//管理层
class mgemployee extends employee{
override var name: String = _
override var pay: Double = _
var bonus:Double= _
override def getAnnual: Double =
{
pay*12+bonus
}
def manage(): Unit ={
println(name+" is a manager")
}
}
}