快学scala-第七章 包和引入
知识点:
1. Scala、Java、C++的包的目的都是为了管理大型程序中的名称。与对象或类的定义不同,同一个包可以定义在多个文件当中。或者在同一个文件中,为多个包贡献内容。
2. Scala的包和其他作用域一样的支持嵌套,可以访问上层作用域中的名称。Scala会遇到默认引入包中的类和自定义包中的类的冲突问题,Java中不会出现这样的问题,包名总是绝对的,从包层级的最顶端开始,但是在Scala中,包名是相对的,就像内部类的名称一样。任何人都可以在任何时候向任何包添加内容。
3. 串联式包语句 com.horstmann.impatient 这样的包语句限定了可见的成员,文件顶部标记法是在文件顶部使用package语句,这比较适用于文件中所有代码属于同一个包的情况。
4. 包对象,包可以包含类、对象和特质,但不能包含函数或变量的定义,这是Java虚拟机的局限,包对象解决了这个局限。每个包都可以有一个包对象,需要在父包中定义它,且名称与子包一样,包对象被编译成带有静态方法和字段的JVM类,名为package.class,位于相应的包下。
5. 包可见性,在Java中,没有被声明为public、private或protected的类成员在包含该类的包中可见,在Scala中,可以通过修饰符达到同样的效果。
pacage com.horstmann.impatient.people
private[people] ….(自己的包中可见)
private[impatient]….(上层包,将可见性扩展到上层包)
6. 引入语句可以使用更短的名称而不是原来较长的名称,引入某个包的全部成员,使用类似于import java.awt._, 这和Java中的通配符*一样,在Scala中,*是合法的标识符。在Scala中,任何地方都可以声明引入,import语句效果一直延伸到包含该语句的块末尾。通过将引入放置在需要这些引入的地方可以大幅减少可能的名称冲突。
如果想要引入包中的几个成员,可以使用选取器,eg: import java.awt.{Color,Font}
选取器语法还允许重命名选到的成员,eg:
import java.util.{HashMap => JavaHashMap}
import scala.collection.mutable._
JavaHashMap就是java.util.HashMap,而HashMap则对应scala.collection.mutable.HashMap.
7.隐式引入,每个Scala程序都隐式地以如下代码开始:
import java.lang._
import scala._
import Predef._
这个引入被允许覆盖。
练习:参考网址
1.编写示例程序,展示为什么
package com.horstmann.impatient
不同于
package com
package horstmann
package impatient
第一种方式子类不可以使用父包里的类.
package com{ class T1(){} package horstmann{ class T2(t:T1){} package impatient{ class T3(t1:T1,t2:T2){} } } } package com.horstmann.impatient{ class T4(t1:T1,t3:T3){}//not found:type T1 }
2.编写一段让你的Scala朋友们感到困惑的代码,使用一个不在顶部的com包
不懂.
3.编写一个包random,加入函数nextInt():Int,nextDouble():Double,setSeed(seed:Int):Unit。生成随机数的算法采用线性同余生成器:
后值 = (前值 * a + b)mod 2^n
其中,a = 1664525,b=1013904223,n = 32,前值的初始值为seed
package random{ package object random{ var seed:Int = _ val a = BigDecimal(1664525) val b = BigDecimal(1013904223) val n = 32 def nextInt:Int={ var temp = (seed * a + b) % BigDecimal(2).pow(n) seed = temp.toInt seed } def nextDouble:Double={ var temp = (seed * a + b) % BigDecimal(2).pow(n) seed = temp.toInt temp.toDouble } } } package test{ import random.random object Test extends App{ random.seed = 4 println(random.nextInt) println(random.nextInt) println(random.nextInt) println(random.nextDouble) println(random.nextDouble) println(random.nextDouble) } }
4.在你看来Scala的设计者为什么要提供package object语法而不是简单的让你将函数和变量添加到包中呢?
虚拟机的局限
5.private[com] def giveRaise(rate:Double)的含义是什么?有用吗?
private[com]定义包可见性,除了com包其他包都不能访问。
6.编写一段程序,将Java哈希映射中的所有元素拷贝到Scala哈希映射。用引入语句重命名这两个类.
import java.util.{HashMap => JavaHashMap} import scala.collection.mutable.HashMap object Test extends App{ val map = new JavaHashMap[String,String]() map.put("1", "a") map.put("2", "b") map.put("3", "c") val smap = new HashMap[String,String]() for(key <- map.keySet().toArray){ smap += (key.toString() -> map.get(key)) } println(smap.mkString) }
7.在前一个练习中,将所有引入语句移动到尽可能小的作用域里.
object Test extends App{ import java.util.{HashMap => JavaHashMap} val map = new JavaHashMap[String,String]() map.put("1", "a") map.put("2", "b") map.put("3", "c") import scala.collection.mutable.HashMap val smap = new HashMap[String,String]() for(key <- map.keySet().toArray){ smap += (key.toString() -> map.get(key)) } println(smap.mkString) }
8.以下代码的作用是什么?这是个好主意吗?
import java._
import javax._
导入Java和javax中的所有类,这两个包中中只有子包,不包含类,所以无用。
9.编写一段程序,引入java.lang.System类,从user.name系统属性读取用户名,从Console对象读取一个密码,如果密码不是"secret",则在标准错误流中打印一个消息;如果密码是"secret",则在标准输出流中打印一个问候消息。不要使用任何其他引入,也不要使用任何限定词(带句点的那种).
import java.lang.System object Test extends App{ val password = Console.readInt if(password equals "secret") System.out.println("Hello " + System.getProperty("user.name")) else System.err.println("password error") }