包和引入(三)

包的作用和定義

同java中的包,Scala中的包主要用於大型工程代碼的組織同時也解決命名衝突的問
題。Scala中的包與java有着諸多的相似之處,但Scala語言中的包更加靈活。

  • 包定義方式一:
//將代碼組織到cn.scala.xtwy包中
package cn.scala.xtwy

abstract class Animal {
  //抽象字段(域)
  var height:Int
  //抽象方法
  def eat:Unit
}

class Person(var height:Int) extends Animal{
  override def eat()={
    println("eat by mouth")
  }

}

object Person extends App{
  new Person(10).eat()
}
  • 包定義方式二:
    //下面的代碼定義了一個cn.scala.xtwy包
    //在程序的任何地方都可以通過cn.scala.xtwy.Teacher來使用Teacher這個類
package cn{
  package scala{
    package xtwy{
      class Teacher {

      }
    }
  }
}

可以看出,我們可以在任何地方進行包中類的定義,scala幫助我們進行自動文件組織
我們將Teacher.scala內容修改如下:

package cn{
  package scala{
    package xtwy{
      class Teacher {

      }
    }
  }
}

//添加了cn.scala.spark包,包中定義了一個SparkDemo類

package cn{
  package scala{
    package spark{
      class SparkDemo{

      }
    }
  }
}

通過前面的介紹,我們知道了如何定義包,包是怎麼組織代碼的。在實際開發過程當中,儘量使用java包的定義方式並將代碼集中進行管理,這樣別人讀代碼的時候更方便,代碼更簡潔。

包的作用域與引入(import)的使用方法

下面的代碼給出了包的作用域和引入的使用方法

package cn{
  package scala{
    //在包cn.scala下創建了一個Utils單例
    object Utils{
      def toString(x:String){
        println(x)
      }
      //外層包無法直接訪問內層包,下面這一行代碼編譯通不過
     //def getTeacher():Teacher=new Teacher("john")
     //如果一定要使用的話,可以引入包
     import cn.scala.xtwy._
     def getTeacher():Teacher=new Teacher("john")
    }
    //定義了cn.scala.xtwy
    package xtwy{
      class Teacher(var name:String) {
           //演示包的訪問規則
           //內層包可以訪問外層包中定義的類或對象,無需引入
           def printName()={Utils.toString(name)}
      }

    }
  }
}
object appDemo{
        //scala允許在任何地方進行包的引入,_的意思是引入該包下的所有類和對象
        import cn.scala._
        import cn.scala.xtwy._
        def main(args: Array[String]): Unit = {
            Utils.toString(new Teacher("john").name)
            new Teacher("john").printName() 
        }

}

Scala訪問修飾符

Scala 訪問修飾符分別有:private,protected,public。

如果沒有指定訪問修飾符符,默認情況下,Scala 對象的訪問級別都是 public。

Scala 中的 private 限定符,比 Java 更嚴格,在嵌套類情況下,外層類甚至不能訪問被嵌套類的私有成員。

私有(Private)成員

用private關鍵字修飾,帶有此標記的成員僅在包含了成員定義的類或對象內部可見,同樣的規則還適用內部類。

class Outer{
        class Inner{
        private def f(){println("f")}
        class InnerMost{
            f() // 正確
            }
        }
        (new Inner).f() //錯誤
}

(new Inner).f( )訪問不合法是因爲f在Inner中被聲明爲private,而訪問不在類Inner之內。

保護(Protected)成員

在scala中,只允許保護成員在定義了該成員的的類的子類中被訪問。

package p{
        class Super{
            protected def f() {println("f")}
        }
        class Sub extends Super{
            f()
        }
        class Other{
            (new Super).f() //錯誤
        }
}

上例中,Sub 類對 f 的訪問沒有問題,因爲 f 在 Super 中被聲明爲 protected,而 Sub 是 Super 的子類。相反,Other 對 f 的訪問不被允許,因爲 other 沒有繼承自 Super。

公共(Public)成員

Scala中,如果沒有指定任何的修飾符,則默認爲public。這樣的成員在任何地方都可以被訪問。

class Outer {
       class Inner {
              def f() { println("f") }
              class InnerMost {
                     f() // 正確
              }
       }
       (new Inner).f() // 正確因爲 f() 是 public
}

作用域保護

Scala中,訪問修飾符可以通過使用限定詞強調。格式爲:

private[x]

protected[x]

這裏的x指代某個所屬的包、類或單例對象。如果寫成private[x],讀作”這個成員除了對[…]中的類或[…]中的包中的類及它們的伴生對像可見外,對其它所有類都是private。

這種技巧在橫跨了若干包的大型項目中非常有用,它允許你定義一些在你項目的若干子包中可見但對於項目外部的客戶卻始終不可見的東西。

package bobsrocckets{
    package navigation{
        private[bobsrockets] class Navigator{
         protected[navigation] def useStarChart(){}
         class LegOfJourney{
             private[Navigator] val distance = 100
             }
            private[this] var speed = 200
            }
        }
        package launch{
        import navigation._
        object Vehicle{
        private[launch] val guide = new Navigator
        }
    }
}

上述例子中,類Navigator被標記爲private[bobsrockets]就是說這個類對包含在bobsrockets包裏的所有的類和對象可見。

比如說,從Vehicle對象裏對Navigator的訪問是被允許的,因爲對象Vehicle包含在包launch中,而launch包在bobsrockets中,相反,所有在包bobsrockets之外的代碼都不能訪問類Navigator。

下面給出的是訪問規則表

修飾符 訪問範圍
無任何修飾符 任何地方都可以使用
private[scala] 在定義的類中可以訪問,在scala包及子包中可以訪問
private[this] 只能在定義的類中訪問,即使伴生對象也不能訪問團
private 在定義的的類及伴生對象中可以訪問,其它地方不能訪問
protected[scala] 在定義的類及子類中可以訪問,在scala包及子包中可以訪問
protected[this] 只能在定義的類及子類中訪問,即使伴生對象也不能訪問
protected 在定義的類及子類中訪問,伴生對象可以訪問,其它地方不能訪問

包對象

包對象主要用於將常量、工具函數,使用時直接通過包名引用

//下面的代碼給出了包對象的定義
package cn.scala.xtwy

//利用package關鍵字定義單例對象
package object Math {
  val PI=3.141529
  val THETA=2.0
  val SIGMA=1.9
}

class Coputation{
  def computeArea(r:Double)=Math.PI*r*r
}

import高級特性

  • 隱式引入
    在集合那一講,我們提到,如果不引入任何包,scala會默認引入java.lang._
    scala._
    Predef._
    包中或對象中所有的類和方法,稱這種引入會隱式引入
  • 重命名
    scala中允許對引入的類或方法進行重命名,如果我們需要在程序中同時使用java.util.HashMap及scala.collection.mutable.HashMap時,可以利用重命名的方法消除命名衝突的問題,雖然也可以採用包名前綴的方式使用,但代碼不夠簡潔
//將java.util.HashMap重命名爲JavaHashMap
import java.util.{ HashMap => JavaHashMap }
import scala.collection.mutable.HashMap
object RenameUsage {
  def main(args: Array[String]): Unit = {
    val javaHashMap = new JavaHashMap[String, String]()
    javaHashMap.put("Spark", "excellent")
    javaHashMap.put("MapReduce", "good")
    for(key <- javaHashMap.keySet().toArray){
      println(key+":"+javaHashMap.get(key))
    }

    val scalaHashMap=new HashMap[String,String]
    scalaHashMap.put("Spark", "excellent")
    scalaHashMap.put("MapReduce", "good")
    scalaHashMap.foreach(e=>{
      val (k,v)=e
      println(k+":"+v)
    })
  }

}
  • 隱藏類
//通過HashMap=> _,這樣類便被隱藏起來了
import java.util.{HashMap=> _,_}
import scala.collection.mutable.HashMap


object RenameUsage {
  def main(args: Array[String]): Unit = {

    //這樣的話,HashMap便無歧義地指向scala.collection.mutable.HashMap
    val scalaHashMap=new HashMap[String,String]
    scalaHashMap.put("Spark", "excellent")
    scalaHashMap.put("MapReduce", "good")
    scalaHashMap.foreach(e=>{
      val (k,v)=e
      println(k+":"+v)
    })
  }

忠於技術,熱愛分享。歡迎關注公衆號:java大數據編程,瞭解更多技術內容。

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章