包
1
1.基本语法
package 包名
2.Scala包的三大作用(和Java一样)
1) 区分相同名字的类
2) 当类很多时,可以很好的管理类
3) 控制访问范围
3.Scala中包名和源码所在的系统文件目录结构要可以不一致但是编译后的字节码文件路径和包名会保持一致(这个 工作由编译器完成)。
//命名规则
只能包含数字、字母、下划线、小圆点.,但不能用数字开头, 也不要使用关键字。
demo.class.exec1 //错误 , 因为class是关键字demo.12a // 错误因为不能以数字开头
//命名规范
一般是小写字母+小圆点一般是
com.公司名.项目名.业务模块名比如com.oa.model com.oa.controller
com.sina.edu.user
com.sohu.bank.order
package com.scala
class Person{
val name = "Nick"
def play(message: String): Unit ={println(this.name + " " + message)
}
}
代码说明 传统的方式
//等同于
package com
package scala
class Person{
val name = "Nick"
def play(message: String): Unit ={println(this.name + " " + message)
}
}
代码说明 和第一种方式完全等价
2.包中有包
包也可以像嵌套类那样嵌套使用包中有包, 这个在前面的第三种打包方式已经讲过了在使用第三种方式时的好处是程序员可以在同一个文件中将类(class / object)、trait 创建在不同的包中这样就非常灵活了。[案例+反编译]
////代码说明
//1. package com.hainiu{} 表示我们创建了包 com.hainiu ,在{}中
// 我们可以继续写它的子包 scala //com.hainiu.scala, 还可以写类,特质trait,还可以写object
//2. 即sacla支持在一个文件中可以同时创建多个包以及给各个包创建类,trait和object
package com.hainiu { //包 com.hainiu
// class User { // 在com.hainiu User类
// def sayHello(): Unit = {
// //想使用 com.hainiu.scala2包下的 Monster
// import com.hainiu.scala2.Monster
// val monster = new Monster()
// }
// }
//
// package scala2 { // 创建包 com.hainiu.scala2
// class User { // 在com.hainiu.scala2 包下创建个 User类
// }
//
// class Monster { //
//
// }
//
// }
//
//说明
//1. 在包中直接写方法或者定义变量就错误==>使用包对象的技术来解决
//2. package object scala 表示创建一个包对象 scala, 他是 com.hainiu.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.hainiu.scala
class Person { // 表示在 com.hainiu.scala下创建类 Person
val name = "Nick"
def play(message: String): Unit = {
println(this.name + " " + message)
}
}
class User {
def testUser(): Unit = {
println("name = " + name)
sayHiv()
}
}
object Test100 { //表示在 com.hainiu.scala 创建object Test
def main(args: Array[String]): Unit = {
println("name=" + name)
name = "yy"
sayHiv()
// println("ok")
// //我们可以直接使用父包的内容
// //1.如果有同名的类则采用就近原则来使用内容(比如包)
// //2.如果就是要使用父包的类则指定路径即可
// val user = new User
// println("user=" + user) //
// val user2 = new com.hainiu.User()
// println("user2" + user2)
}
}
}
}
3.作用域原则
子包可以访问父包中的类如果子包中有和父类中同样的类名则带上父包的具体路径
val user2 = new com.hainiu.User()
作用域原则可以直接向上访问。即: Scala中子包中直接访问父包中的内容, 大括号体现作用域。(提示Java中子包使用父包的类需要import)。在子包和父包 类重名时默认采用就近原则如果希望指定使用某个类则带上包名即可。【案例演示+反编译】
4父包要访问子包的内容时需要import对应的类等
package com.hainiu{
//引入在com.hainiu 包中希望使用到子包的类Tiger,因此需要引入.
import com.hainiu.scala.Tiger
//这个类就是在com.hainiu
class User{
}
package scala {
//Tiger 在 com.hainiu.scala 包中
class Tiger {}}
object Test2 {
def main(args: Array[String]): Unit = {
//如果要在父包使用到子包的类需要import
val tiger = new Tiger()
println("tiger=" + tiger)
}}}
5.package层数不要超过3层
可以在同一个.scala文件中声明多个并列的package(建议嵌套的pakage不要超过3层)
6.包名可以相对也可以绝对
比如访问BeanProperty的绝对路径是_root_. scala.beans.BeanProperty 在一般情况下我们使用相对路径来引入包只有当包名冲突时使用绝对路径来处理。
package com.hainiu.scala2
class Manager( var name : String ) {
//第一种形式
//@BeanProperty var age: Int = _
//第二种形式, 和第一种一样都是相对路径引入
//@scala.beans.BeanProperty var age: Int = _
//第三种形式, 是绝对路径引入可以解决包名冲突
@_root_. scala.beans.BeanProperty var age: Int = _
}
object TestBean {
def main(args: Array[String]): Unit = {
val m = new Manager("jack")
println("m=" + m)
}}
7.包对象
保重不能建立类通过object 建立包对象在包对象中建立对象和属性。 然后共子包调用
基本介绍包可以包含类、对象和特质trait但不能包含函数/方法或变量的定义。这是Java虚拟机的局限。为了弥补这一点不足scala提供了包对象的概念来解决这个问题。
package com.hainiu {
//每个包都可以有一个包对象。你需要在父包(com.hainiu)中定义它,且名称与子包一样。
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)
}}}}
7.1包对象的注意事项
1.每个包都可以有一个包对象。你需要在父包中定义它。
2.包对象名称需要和包名一致一般用来对包的功能补充
8.包的可见性
伴生类 类的参数是父类的类型为伴生对象
1.当属性访问权限为默认时从底层看属性是private的但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter] 方法因此从使用效果看是任何地方都可以访问)
2.当方法访问权限为默认时默认为public访问权限
3.private为私有权限只在类的内部和伴生对象中可用 【案例演示】
4.protected为受保护权限scala中受保护权限比Java中更严格只能子类访问同包无法访问 (编译器)
5.在scala中没有public关键字,即不能用public显式的修饰属性和方法。
6.包访问权限表示属性有了限制。同时包也有了限制这点和Java不一样体现出Scala包使用的灵活性。
包访问权限在private的[------]中增加包的某一级名字 ,属性名加上private类名后也会加上
package com.hn.scala
class Person {
private[scala] val pname="hello" // 增加包访问权限后1.private同时起作用。不仅同类可以使用 2. 同时com.hn.scala中包下其他类也可以使用
}
当然也可以将可见度延展到上层包
private[scala] val description="zhangsan"
说明private也可以变化比如protected[hn], 非常的灵活。
package com.hainiu {
package com.hainiu.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. 伴生类 写非静态的内容 伴生对象 就是静态内容
//5.
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"
}
9.包的引入
1.在Scala中import语句可以出现在任何地方并不仅限于文件顶部import语句的作用一直延伸到包含该语句的块末尾。这种语法的好处是在需要时在引入包缩小import 包的作用范围提高效率。
class User {
import scala.beans.BeanProperty //在需要时才引入作用域在{}
@BeanProperty var name : String = "" //这里引得包只在这里本类中有用
}
class Dog {
@BeanProperty var name : String = "" //报错
}
2.Java中如果想要导入包中所有的类可以通过通配符*Scala中采用下 _
3.如果不想要某个包中全部的类而是其中的几个类可以采用选取器(大括号)
//只引入mutable 下的{HashMap, HashSet}两个包
def test(): Unit = {
import scala.collection.mutable.{HashMap, HashSet}
var map = new HashMap()
var set = new HashSet()
}
4.如果引入的多个包中含有相同的类那么可以将不需要的类进行重命名进行区分这个就是重命名。
import java.util.{ HashMap=>JavaHashMap, List}
import scala.collection.mutable._
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap
var map1 = new JavaHashMap(); // 此时使用的java中hashMap的别名
5.如果某个冲突的类根本就不会用到那么这个类可以直接隐藏掉
//第一个_是隐藏掉HashMap,第二个_是引入除了hashmap的
所有包import java.util.{ HashMap=>_, _} // 含义为 引入java.util包的所有类但是忽略 HahsMap类.
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap, 而且idea工具的提示也不会显示java.util的HashMaple
面向对象编程方法-抽象
重写override
scala明确规定重写一个非抽象方法需要用override修饰符调用超类的方法使用super关键字
class Person {
var name : String = "tom"
def printName() {
println("Person printName() " + name)
}
}
class Emp extends Person {
//这里需要显式的使用override
override def printName() {
println("Emp printName() " + name)
super.printName()
}
}
Scala中类型检查和转换
基本介绍
1.要测试某个对象是否属于某个给定的类可以用isInstanceOf方法。
用asInstanceOf方法将引用转换为子类的引用。classOf获取对象的类名。
1.classOf[String]就如同Java的 String.class 。
2.obj.isInstanceOf[T]就如同Java的obj instanceof T 判断obj是不是T类型。
3.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] //p1转为子类
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 = {
}
Scala中超类的构造
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")
println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
//再测试一把
//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("默认的名字")
}