scala系列(六)包和引入 有更新!

  |   0 评论   |   1,416 浏览

37套精品Java架构师高并发高性能高可用分布式集群电商缓存性能调优设计项目实战视教程 置顶! 有更新!

(一)包的作用与定义

Java中的包、C++中的命名空间一样,Scala中的包主要用于大型工程代码的组织同时也解决命名冲突的问题。scala中的包与java有着诸多的相似之处,但Scala语言中的包更加灵活。

package com.boom.scala.s6.tt

 

//将代码组织到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()

}

上述包也可通过下面的包定义方式进行:

package com{

  package boom{

    package scala{

      package s6{

        package tt{

          //将代码组织到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()

          }

          

        }

      }

    }

  }

}

 

 

 

将上面的代码命名为Package.scala,代码组织如下: 

可以看到我们将代码放在com.boom.scala.s6下面,但编码后的字节码文件被自动组织到com.boom.scala.s6.tt文件夹当中,如下图 


  可以看出,我们可以在任何地方进行包中类的定义,scala帮助我们进行自动文件组织

我们将上述Package.scala内容修改如下:

package com{

  package boom{

    package scala{

      package s6{

        package tt{

          class Person{}

        }

      }

    }

  }

}

 

package com.boom.scala.s6.xx{

class Ptest{}

}

 

 

 

下图给出的是Package.scala编译后产生的包文件: 


通过前面的介绍,我们知道了如何定义包,包是怎么组织代码的。在实际开发过程当中,尽量使用java包的定义方式并将代码集中进行管理,这样别人读代码的时候更方便,代码更简洁。

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

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

package com.boom.scala.s6

 

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() 

        }

 

}

 

(三)访问控制

java语言中,主要通过public、private、protected及默认控制来实现包中类成员的访问控制,当定义一个类时,如果类成员不加任何访问控制符时,表示该类成员在定义该类的包中可见。在scala中没有public关键字,仅有private 和 protected访问控制符,当一个类成员不加private和protected时,它的访问权限就是public。

n private 成员

private成员同java是一样的,所有带该关键字修饰的成员仅能在定义它的类或对象中使用,在外部是不可见的

class Student(var name:String,var age:Int){

  private var sex:Int=0

  //内部类

  class Course(val cName:String,val gpa:Float){

    //可以直接访问其外部类的私有成员

    def getStudentSex(student:Student)= student.sex

  }

}

 

//班级类

class Class{

  //下面这条语句统计通不过,因为sex是私有的

  // def getStudentSex(student:Student)=student.sex

}

object Student {

  private var studentNo:Int=0;

  def uniqueStudentNo()={

    studentNo+=1

    studentNo

  }

  def apply(name:String,age:Int)=new Student(name,age)

 

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

    println(Student.uniqueStudentNo())

    val s=new Student("john",29)

    //直接访问伴生类Student中的私有成员

    println(s.sex)

 

    val s1=Student("john",29)

    println(s1.name)

    println(s1.age)

 

    //使用内部类

    val c1=new s1.Course("Scala",3.0f)

 

  }

}

 

n protected 成员 

java语言中,protected成员不但可以被该类及其子类访问,也可以被同一个包中的其它类使用,但在scala中,protected成员只能被该类及其子类访问

class SuperClass {

  protected def f()=println(".....")

}

class SubClass extends SuperClass{

  f()

}

class OtherClass{

  //下面这个语句会报错

  //f()

}

n 无修饰符成员 
无修饰符的成员同java 的public,可以在任何位置进行访问

n 范围保护 

scala中提供了更为灵活的访问控制方法,private、protected除了可以直接修饰成员外,还可以以private[X]、protected[X]的方式进行更为灵活的访问控制,这种访问控制的意思是可以将private、protected限定到X,X可以是包、类,还可以是单例对象

package cn{

  class UtilsTest{

     //编译通不过,因为Utils利用private[scala]修饰,只能在scala及其子包中使用

    //Utils.toString()

  }

  package scala{

    //private[scala]限定Utils只能在scala及子包中使用

    private[scala] object Utils{

      def toString(x:String){

        println(x)

      }

      import cn.scala.xtwy._

      def getTeacher():Teacher=new Teacher("john")

 

    }

    package xtwy{

      class Teacher(var name:String) {

           def printName()={Utils.toString(name)}

      }

 

    }

  }

}

object appDemo{

        import cn.scala._

        import cn.scala.xtwy._

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

            //编译通不过,同UtilsTest

            //Utils.toString(new Teacher("john").name)

            new Teacher("john").printName() 

        }

 

}

private[this],限定只有该类的对象才能访问,称这种成员为对象私有成员

package cn.scala.xtwy;

class Teacher(var name: String) {

  private[thisdef printName(tName:String="") :Unit= { println(tName) }

  //调用private[this] printName方法

  def print(n:String)=this.printName(n)

}

object Teacher{

   //private[this]限定的成员,即使伴生对象Teacher也不能使用

  //def printName=new Teacher("john").printName()

}

object appDemo {

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

          //编译不能通过

         //new Teacher("john").printName()

  }

 

}

n private,定义的类及伴生对象可以访问

package cn.scala.xtwy;

class Teacher(var name: String) {

  private def printName(tName:String="") :Unit= { println(tName) }

  //可以访问

  def print(n:String)=this.printName(n)

}

object Teacher{

  //伴生对象可以访问

  def printName=new Teacher("john").printName()

}

object appDemo {

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

          //不能访问

         //new Teacher("john").printName()

  }

 

}

 

n 访问规则表

修饰符

访问范围

无任何修饰符

任何地方都可以使用

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

}

 

上述代码编译后会生成下列文件: 

对应字节码文件如下:

D:\ScalaWorkspace\ScalaChapter08\bin\cn\scala\xtwy\Math>javap -private package.c

lass

Compiled from "Math.scala"public final class cn.scala.xtwy.Math.package {

  public static double SIGMA();

  public static double THETA();

  public static double PI();

}

 

D:\ScalaWorkspace\ScalaChapter08\bin\cn\scala\xtwy\Math>javap -private package$.class

Compiled from "Math.scala"public final class cn.scala.xtwy.Math.package$ {

  public static final cn.scala.xtwy.Math.package$ MODULE$;

  private final double PI;

  private final double THETA;

  private final double SIGMA;

  public static {};

  public double PI();

  public double THETA();

  public double SIGMA();

  private cn.scala.xtwy.Math.package$();

}

可以看出,它为我们的包对象Math创建了一个文件夹,然后创建了两个类,通过单例的方式实现方法调用。

(五)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)

    })

  }

(六)内部类

前面我们提到过内部类,我们看到内部类可以像类的其它成员一样访问外部类的私有成员,本小节将对内部类进行更加详细的介绍。

外部类不能访问内部类的成员域,但内部类可以直接访问外部类成员域,哪怕这个成员域是private私有的

class OuterClass {

  //即使定义为 private[this] var x:Int=0,也是可行的

  private var x:Int=0

 

  //def getInnerY=y,外部类不能直接访问内部类的成员域

  class InnerClass{

    private var y:Int=0

    //内部的类可以直接访问外部类的成员变量和成员方法,注意外部类的成员变量是private

    def getOuterX= x

  }

}

object AppDemo{

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

    val o=new OuterClass

    //创建内部类对象,通过o.InnerClass方式,InnerClass就像是OuterClass的成员变量一样

    val i=new o.InnerClass

    println(i.getOuterX)

  }

}

 

从上述代码可以看出,内部类除了是一个类之外,与外部类的成员没有任何区别,它可以与外部类的成员域一样被使用


评论

发表评论

validate