天天看點

ScalaNote06-包相關

包基礎概念

  現在有兩個程式員共同開發一個項目,程式員小明希望定義一個類取名 Dog ,程式員小紅也想定義一個類也叫Dog,我們知道同一個腳本裡類名不可以一樣。這時可以使用包進行區分,并且控制通路範圍。一般大家會用IDEA開發scala代碼,此時可以通過子包的方式,分别存放Dog類的檔案。調用時,帶上路徑即可,比如:

val dog1 = new scala.xiaoming.Dog
val dog2 = new scala.xiaohong.Dog      

包的命名

命名規則

  • 隻能包含數字、字母、下劃線、小圓點
  • 不能用數字開頭, 也不要使用關鍵字

命名規範

一般是小寫字母+小圓點一般是com.公司名.項目名.業務子產品名,比如百度機器學習的ctr項目:com.baidu.ml.ctr

包的使用細節

  使用細節視訊上講了很多,但是目前我自己用到的很少,是以簡單列幾個點:

  • Scala中子包中直接通路父包中的内容, 大括号展現作用域
  • 在子包和父包 類重名時,預設采用就近原則,如果希望指定使用某個類,則帶上包名即可
  • 父包要通路子包的内容時,需要import對應的類等
package com.atguigu{
  //這個類就是在com.atguigu包下
  class User{
  }
  //這個類對象就是在Monster$ , 也在com.atguigu包下
  object Monster {
  }
  class Dog {
  }
  package scala {
    //這個類就是在com.atguigu.scala包下
    class User{
    }
    //這個Test 類對象
    object Test {
      def main(args: Array[String]): Unit = {
          //子類可以直接通路父類的内容
          var dog = new Dog()
          println("dog=" + dog)
          //在子包和父包 類重名時,預設采用就近原則.
          var u = new User()
          println("u=" + u)
          //在子包和父包 類重名時,如果希望指定使用某個類,則帶上包路徑
          var u2 = new com.atguigu.User()
          println("u2=" + u2)
      }
    }
  }
}       

上面這個例子我都沒遇到過,通常都是把不同的object腳本,放在一個子包下面,暫時先這樣,後面實際工作中遇到再來填坑。

包對象

  包可以包含類、對象和特質trait,但不能包含函數/方法或變量的定義。這是Java虛拟機的局限。為了彌補這一點不足,scala提供了包對象的概念來解決這個問題。在實際開發中,我也沒有用過包對象,是以還是簡單看下代碼吧~

package com.atguigu {  
  //每個包都可以有一個包對象。你需要在父包(com.atguigu)中定義它,且名稱與子包一樣。
  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)
      }}}}      

如上面代碼:

  • com.atguigu下面有一個scala的子包
  • scala子包下面有一個類Test,一個object TestObj
  • 在子包scala同級處,定義了個包對象(package object scala)
  • 每個包都可以有一個包對象,需要在父包中定義它,也就是和子包同級
  • 包對象名稱需要和包名一緻,一般用來對包的功能補充,比如子包scala的包對象用package object scala{}定義

包的可見性

package com.atguigu.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"
}
      
  1. 當屬性通路權限為預設時,從底層看屬性是private的,但是因為提供了xxx_$eq()[類似setter]/xxx()[類似getter] 方法,是以從使用效果看是任何地方都可以通路)
  2. 當方法通路權限為預設時,預設為public通路權限

    上面兩點好像隻是概念上的差別,用法上都可以直接通路

  3. private為私有權限,隻在類的内部和伴生對象中可用

    第3點需要注意,class Clerk為伴生類,object Clerk 為伴生對象,私有變量sal隻能在伴生對象中使用

  4. protected為受保護權限,scala中受保護權限比Java中更嚴格,隻能子類通路,同包無法通路 (編譯器)

    第4點,在Person類中,name變量有protected修飾,此時隻能子類通路,但是加上[visit]之後,可以在visit包中使用

  5. 在scala中沒有public關鍵字,即不能用public顯式的修飾屬性和方法

包的引入

  • 在Scala中,import語句可以出現在任何地方,并不僅限于檔案頂部,import語句的作用一直延伸到包含該語句的塊末尾。這種文法的好處是:在需要時在引入包,縮小import 包的作用範圍,提高效率
  • 導入包中所有的類,Scala中采用下 _ ,如 import org.apache.spark.sql.functions._
  • 導入包中部分類,import org.apache.log4j.{Level, Logger}
  • 給導入的類重命名,import java.util.{ HashMap=>JavaHashMap, List},這裡指把java.util中的HashMap重命名為JavaHashMap
  • 如果某個沖突的類根本就不會用到,那麼這個類可以直接隐藏掉,import java.util.{ HashMap=>_, _} // 含義為 引入java.util包的所有類,但是忽略 HahsMap類