1、scala包
1.1、基本语法
package 包名
1.2、包的作用(和java一样)
- 区分相同名字的类
- 当类很多时,可以很好的管理类
- 控制访问范围
- 可以对类的功能进行扩展
1.3、命名规则
只能包含数字、字母、下划线、小圆点.,但不能用数字开头, 也不要使用关键字。
demo.class.exec1 //错误 , 因为class是关键字
demo.12a // 错误,因为不能以数字开头
1.4、自动引入的常用包
- java.lang.*
- scala包
- predef包
1.5、注意事项
① scala在一个文件中可以创建多个包以及给各个包创建类,trait和object
//1. package com.nuc{} 表示我们创建了包 com.nuc ,在{}中
// 我们可以继续写它的子包 scala //com.nuc.scala, 还可以写类,特质trait,还可以写object
//2. 即sacla支持,在一个文件中,可以同时创建多个包,以及给各个包创建类,trait和object
package com.nuc { //包 com.nuc
package scala { //包 com.nuc.scala
class Person { // 表示在 com.nuc.scala下创建类 Person
val name = "Nick"
def play(message: String): Unit = {
println(this.name + " " + message)
}
}
object Test100 { //表示在 com.nuc.scala 创建object Test
def main(args: Array[String]): Unit = {
println("ok")
}
}
}
}
//1. package com.nuc{} 表示我们创建了包 com.nuc ,在{}中
// 我们可以继续写它的子包 scala //com.nuc.scala, 还可以写类,特质trait,还可以写object
//2. 即sacla支持,在一个文件中,可以同时创建多个包,以及给各个包创建类,trait和object
package com.nuc { //包 com.nuc
class User { // 在com.nuc包下创建个 User类
}
package scala2 { // 创建包 com.nuc.scala2
class User { // 在com.nuc.scala2 包下创建个 User类
}
}
package scala { //包 com.nuc.scala
class Person { // 表示在 com.nuc.scala下创建类 Person
val name = "Nick"
def play(message: String): Unit = {
println(this.name + " " + message)
}
}
object Test100 { //表示在 com.nuc.scala 创建object Test
def main(args: Array[String]): Unit = {
println("ok")
}
}
}
}
②作用域:可以直接向上访问。即: Scala中子包中直接访问父包中的内容, 大括号体现作用域。(提示:Java中子包使用父包的类,需要import)。在子包和父包 类重名时,默认采用就近原则,如果希望指定使用某个类,则带上包名即可
package com.nuc { //包 com.nuc
class User { // 在com.nuc包下创建个 User类
}
package scala2 { // 创建包 com.nuc.scala2
class User { // 在com.nuc.scala2 包下创建个 User类
}
}
package scala {
class Person {
val name = "Nick"
def play(message: String): Unit = {
println(this.name + " " + message)
}
}
class User {
}
object Test100 {
def main(args: Array[String]): Unit = {
println("ok")
//我们可以直接使用父包的内容
//1.如果有同名的类,则采用就近原则来使用内容(比如包)
//2.如果就是要使用父包的类,则指定路径即可
val user = new User
println("user=" + user) //
val user2 = new com.nuc.User()
println("user2" + user2)
}
}
}
}
③父包要访问子包的内容时,需要import对应的类等
package com.nuc { //包 com.nuc
class User { // 在com.nuc包下创建个 User类
def sayHello(): Unit = {
//想使用 com.nuc.scala2包下的 Monster
import com.nuc.scala2.Monster
val monster = new Monster()
}
}
package scala2 { // 创建包 com.nuc.scala2
class User { // 在com.nuc.scala2 包下创建个 User类
}
class Monster{ //
}
}
package scala { //包 com.nuc.scala
class Person { // 表示在 com.nuc.scala下创建类 Person
val name = "Nick"
def play(message: String): Unit = {
println(this.name + " " + message)
}
}
class User {
}
object Test100 { //表示在 com.nuc.scala 创建object Test
def main(args: Array[String]): Unit = {
println("ok")
//我们可以直接使用父包的内容
//1.如果有同名的类,则采用就近原则来使用内容(比如包)
//2.如果就是要使用父包的类,则指定路径即可
val user = new User
println("user=" + user) //
val user2 = new com.nuc.User()
println("user2" + user2)
}
}
}
}
④可以在同一个.scala文件中,声明多个并列的package(建议嵌套的pakage不要超过3层
)
⑤包名可以相对
也可以绝对
,在一般情况下:我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理
package com.nuc.scala2
import scala.beans.BeanProperty
class Manager(var name: String) {
//第一种形式 [使用相对路径引入包]
@BeanProperty var age: Int = _
//第二种形式, 和第一种一样,都是相对路径引入
@scala.beans.BeanProperty var age2: Int = _
//第三种形式, 是绝对路径引入,可以解决包名冲突
@_root_.scala.beans.BeanProperty var age3: Int = _
}
object TestBean {
def main(args: Array[String]): Unit = {
val m = new Manager("jack")
println("m=" + m)
}
}
1.6、包对象
①基本介绍
包可以包含类、对象和特质trait,但不能包含函数/方法或变量的定义。这是Java虚拟机的局限。为了弥补这一点不足,scala提供了包对象的概念来解决这个问题。
②示例
package com.nuc { //包 com.nuc
//说明
//1. 在包中直接写方法,或者定义变量,就错误==>使用包对象的技术来解决
//2. package object scala 表示创建一个包对象 scala, 他是 com.nuc.scala这个包对应的包对象
//3. 每一个包都可以有一个包对象
//4. 包对象的名字需要和子包一样
//5. 在包对象中可以定义变量,方法
//6. 在包对象中定义的变量和方法,就可以在对应的包中使用
//7. 在底层这个包对象会生成两个类 package.class 和 package$.class
package object scala {
var name = "king"
def sayHiv(): Unit = {
println("package object scala sayHI~")
}
}
package scala { //包 com.nuc.scala
class Person { // 表示在 com.nuc.scala下创建类 Person
val name = "Nick"
def play(message: String): Unit = {
println(this.name + " " + message)
}
}
class User {
def testUser(): Unit = {
println("name = " + name)
sayHiv()
}
}
object Test { //表示在 com.nuc.scala 创建object Test
def main(args: Array[String]): Unit = {
println("name=" + name)
name = "yy"
sayHiv()
}
}
}
}
③注意事项
- 每个包都可以有一个包对象。你需要在父包中定义它
- 包对象名称需要和包名一致,一般用来对包的功能补充
1.7、包的可见性
①基本介绍
在Java中,访问权限分为: public,private,protected和默认。在Scala中,你可以通过类似的修饰符达到同样的效果
②示例
object Testvisit {
def main(args: Array[String]): Unit = {
val c = new Clerk()
c.showInfo()
Clerk.test(c)
}}
class Clerk {
var name : String = "jack"
private var sal : Double = 9999.9
def showInfo(): Unit = {
println(" name " + name + " sal= " + sal)
}}
object Clerk{
def test(c : Clerk): Unit = {
//这里体现出在伴生对象中,可以访问c.sal
println("test() name=" + c.name + " sal= " + c.sal)
}
}
1.8、包的引入
① 基本介绍
Scala引入包也是使用import, 基本的原理和机制和Java一样,但是Scala中的import功能更加强大,也更灵活。
因为Scala语言源自于Java,所以java.lang包中的类会自动引入到当前环境中,而Scala中的scala包和Predef包的类也会自动引入到当前环境中,即起其下面的类可以直接使用。
如果想要把其他包中的类引入到当前环境中,需要使用import语言
② 注意事项
1) 在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部,import语句的作用一直延伸到包含该语句的块末尾。这种语法的好处是:在需要时在引入包,缩小import 包的作用范围,提高效率。
class User {
import scala.beans.BeanProperty
@BeanProperty var name : String = ""
}
class Dog {
@BeanProperty var name : String = "" //可以吗? no
}
2) Java中如果想要导入包中所有的类,可以通过通配符*,Scala中采用下 _
3) 如果不想要某个包中全部的类,而是其中的几个类,可以采用选取器(大括号)
def test(): Unit = {
//可以使用选择器,选择引入包的内容,这里,我们只引入 HashMap, HashSet
import scala.collection.mutable.{HashMap, HashSet}
var map = new HashMap()
var set = new HashSet()
}
4) 如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分,这个就是重命名
def test2(): Unit = {
//下面的含义是 将 java.util.HashMap 重命名为 JavaHashMap
import java.util.{ HashMap=>JavaHashMap, List}
import scala.collection.mutable._
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap
var map1 = new JavaHashMap(); // 此时使用的java中hashMap的别名
}
5) 如果某个冲突的类根本就不会用到,那么这个类可以直接隐藏掉
import java.util.{ HashMap=>_, _} // 含义为 引入java.util包的所有类,但是忽略 HahsMap类.
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap, 而且idea工具,的提示也不会显示java.util的HashMaple
2、访问修饰符
①基本介绍
-
当属性访问权限为默认时,从底层看属性是private的,但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter] 方法,因此从使用效果看是任何地方都可以访问)
-
当方法访问权限为默认时,
默认为public访问权限
-
private为私有权限,
只在类的内部和伴生对象中可用
-
protected为受保护权限,scala中受保护权限比Java中更严格,
只能子类访问,同包无法访问
-
在scala中没有public关键字,即不能用public显式的修饰属性和方法。
-
包访问权限(表示属性有了限制。同时包也有了限制),这点和Java不一样,体现出Scala包使用的灵活性
object Demo3 {
def main(args: Array[String]): Unit =
{//增加包访问权限后,不仅同类可以使用,同时nuc包下的其他类也可以使用
val d = new DD
println(d.name)
}
}
class DD{
private[nuc] val name = "hello"
//说明:private也可以变化,比如protected[nuc],非常灵活
}
②综合案例
package com.nuc.chapter07.visit
object Testvisit {
def main(args: Array[String]): Unit = {
val c = new Clerk()
c.showInfo()
Clerk.test(c)
//创建一个Person对象
val p1 = new Person
println(p1.name)
}
}
//类
class Clerk {
var name: String = "jack" //
private var sal: Double = 9999.9
protected var age = 10
var job : String = "大数据工程师"
def showInfo(): Unit = {
//在本类可以使用私有的
println(" name " + name + " sal= " + sal)
}
}
//当一个文件中出现了 class Clerk 和 object Clerk
//1. class Clerk 称为伴生类
//2. object Clerk 的伴生对象
//3. 因为scala设计者将static拿掉, 他就是设计了 伴生类和伴生对象的概念
//4. 伴生类 写非静态的内容 伴生对象 就是静态内容
object Clerk {
def test(c: Clerk): Unit = {
//这里体现出在伴生对象中,可以访问c.sal
println("test() name=" + c.name + " sal= " + c.sal)
}
}
class Person {
//这里我们增加一个包访问权限
//下面private[visit] : 1,仍然是private 2. 在visit包(包括子包)下也可以使用name ,相当于扩大访问范围
protected[visit] val name = "jack"
}
3、scala之继承
① 基本介绍
class 子类名 extends 父类名 { 类体 }
② 示例
object Extends01 {
def main(args: Array[String]): Unit = {
//使用
val student = new Student
student.name = "jack" //调用了student.name() //调用到从Person继承的name()
student.studying()
student.showInfo()
}
}
class Person { //Person类
var name : String = _
var age : Int = _
def showInfo(): Unit = {
println("学生信息如下:")
println("名字:" + this.name)
}
}
//Student类继承Person
class Student extends Person {
def studying(): Unit = {
//这里可以使用父类的属性
println(this.name + "学习 scala中....")
}
}
3.1、重写方法
① 基本介绍
说明: scala明确规定,重写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字
② 示例
object MethodOverride01 {
def main(args: Array[String]): Unit = {
val emp = new Emp100
emp.printName()
}
}
//Person类
class Person100 {
var name: String = "tom"
def printName() { //输出名字
println("Person printName() " + name)
}
def sayHi(): Unit = {
println("sayHi...")
}
}
//这里我们继承Person
class Emp100 extends Person100 {
//这里需要显式的使用override
override def printName() {
println("Emp printName() " + name)
//在子类中需要去调用父类的方法,使用super
super.printName()
sayHi()
}
}
3.2、类型检查和转换
① 基本介绍
要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。用asInstanceOf方法将引用转换为子类的引用。
classOf
获取对象的类名。
② 示例
classOf[String]就如同Java的 String.class
obj.isInstanceOf[T]就如同Java的obj instanceof T 判断obj是不是T类型。
obj.asInstanceOf[T]就如同Java的(T)obj 将obj强转成T类型。
object TypeConvert {
def main(args: Array[String]): Unit = {
//ClassOf的使用,可以得到类名
println(classOf[String]) // 输出
val s = "king"
println(s.getClass.getName) //使用反射机制
//isInstanceOf asInstanceOf
var p1 = new Person200
var emp = new Emp200
//将子类引用给父类(向上转型,自动)
p1 = emp
//将父类的引用重新转成子类引用(多态),即向下转型
var emp2 = p1.asInstanceOf[Emp200]
emp2.sayHello()
}
}
//Person类
class Person200 {
var name: String = "tom"
def printName() { //输出名字
println("Person printName() " + name)
}
def sayHi(): Unit = {
println("sayHi...")
}
}
//这里我们继承Person
class Emp200 extends Person200 {
//这里需要显式的使用override
override def printName() {
println("Emp printName() " + name)
//在子类中需要去调用父类的方法,使用super
super.printName()
sayHi()
}
def sayHello(): Unit = {
}
}
3.3、scala中超类的构造
1)类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用.)
2)
只有主构造器可以调用父类的构造器
。辅助构造器不能直接调用父类的构造器。在Scala的构造器中,你不能调用super(params)
[外链图片转存失败(img-5ke875tq-1566010671630)(D:/work/java/WorkSpace/MarkDown/scala/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/assets/1542887752448.png)]
object ScalaBaseConstrator {
def main(args: Array[String]): Unit = {
//分析一下他的执行流程
//1.因为scala遵守先构建父类部分 extends Person700()
//2.Person...
//val emp = new Emp700()
//分析一下他的执行流程
//1.因为scala遵守先构建父类部分 extends Person700()
//2.Person...
//3.Emp .... (Emp700的主构造器)
println("=====================")
val emp2 = new Emp700("mary")
println("**************************")
//分析执行的顺序
//1.Person...
//2.默认的名字
//3.Emp ....
//4.Emp 辅助构造器~
val emp3 = new Emp700("smith")
//再测试一把
//Person.. , name= "terry"
//Emp ....
val emp4 = new Emp700("terry", 10)
emp4.showInfo() // 雇员的名字 terry
}
}
//父类Person
class Person700(pName:String) {
var name = pName
println("Person...")
def this() {
this("默认的名字")
println("默认的名字")
}
}
//子类Emp继承Person
class Emp700(eName:String,eAge:Int) extends Person700(eName) {
println("Emp ....")
//辅助构造器
def this(name: String) {
this(name,100) // 必须调用主构造器
this.name = name
println("Emp 辅助构造器~")
}
def showInfo(): Unit = {
println("雇员的名字 ", name)
}
}
4、抽象类
① 基本介绍
在Scala中,通过abstract关键字标记不能被实例化的类。方法不用标记abstract,只要省掉方法体即可。抽象类可以拥有抽象字段,抽象字段/属性就是没有初始值的字段
② 示例
object AbstractDemo01 {
def main(args: Array[String]): Unit = {
println("xxx")
}
}
//抽象类
abstract class Animal{
var name : String //抽象的字段
var age : Int // 抽象的字段
var color : String = "black" //普通属性
def cry() //抽象方法,不需要标记 abstract
}
③ 抽象类的注意细节
//默认情况下,一个抽象类是不能实例化的,但是你实例化时,动态的实现了抽象类的所有
//抽象方法,也可以先,如下
val animal = new Animal03 {
override def sayHello(): Unit = {
println("say hello~~~~")
}
}
animal.sayHello()
2) 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
abstract class Animal02 {
//在抽象类中可以有实现的方法
def sayHi (): Unit = {
println("xxx")
}
}
3) 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为abstract
4) 抽象方法不能有主体,不允许使用abstract修饰
5) 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法和抽象属性,除非它自己也声明为abstract类
abstract class Animal03 {
def sayHello()
var food: String
}
class Dog extends Animal03 {
override def sayHello(): Unit = {
println("小狗汪汪叫!")
}
override var food: String = _
}
6) 抽象方法和抽象属性不能使用private、final 来修饰,因为这些关键字都是和重写/实现相违背的
7) 抽象类中可以有实现的方法.
8) 子类重写抽象方法不需要override,写上也不会错.
5、继承层级
[外链图片转存失败(img-yGlelz9B-1566010671632)(D:/work/java/WorkSpace/MarkDown/scala/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/assets/1542888313642.png)]
在scala中,所有其他类都是`AnyRef`的子类,类似Java的Object。
`AnyVal和AnyRef都扩展自Any类`。Any类是根节点
Any中定义了isInstanceOf、asInstanceOf方法,以及哈希方法等。
Null类型的唯一实例就是null对象。可以将null赋值给任何引用,但不能赋值给值类型的变量
Nothing类型没有实例。它对于泛型结构是有用处的,举例:空列表Nil的类型是List[Nothing],它是List[T]的子类型,T可以是任何类。