Scala学习(七)---包和引入
|
包和引入 |
摘要:
在本篇中,你将会了解到Scala中的包和引入语句是如何工作的。相比Java不论是包还是引入都更加符合常规,也更灵活一些。本篇的要点包括:
1. 包也可以像内部类那样嵌套
2. 包路径不是绝对路径
3. 包声明链x.y.z并不自动将中间包x和x.y变成可见
4. 位于文件顶部不带花括号的包声明在整个文件范围内有效
5. 包对象可以持有函数和变量
6. 引入语句可以引入包、类和对象
7. 引入语句可以出现在任何位置
8. 引入语句可以重命名和隐藏特定成员
9. java.lang、scala和Predef总是被引入
|
包 |
Scala中包含义
Scala的包和Java中的包或者C++中的命名空间的目的是相同的:管理大型程序中的名称。举例来说,Map这个名称可以同时出现在scala.collection.immutable和scala. collection.mutable包而不会冲突。要访问它们中的任何一个,你可以使用完全限定的名称scala.collection.immutable.Map或scala.collection.mutable.Map,也可以使用引入语句来提供一个更短小的别名
要增加条目到包中,你可以将其包含在包语句当中,比如:
package com {
package horstmann {
package impatient {
class Employee
…….
}
}
}
这样一来类名Employee就可以在任意位置以com.horstmann.impatient.Employee访问到了
Scala中包定义
与对象或类的定义不同,同一个包可以定义在多个文件当中。前面这段代码可能出现在文件Employee.scala中,而另一个名为Manager.scala的文件可能会包含:
package com {
package horstmann {
package impatient {
class Manager
…….
}
}
}
这说明了,源文件的目录和包之间并没有强制的关联关系。你不需要将Employee.scala和Manager.scala放在com/horstmann/impatient目录当中
换个角度讲,你也可以在同一个文件当中为多个包贡献内容。Employee.scala文件可以包含:
package com {
package horstmann {
package impatient {
class Employee
…….
}
}
}
package org {
package bigjava {
class Counter
…….
}
}
|
作用域规则 |
包嵌套
在Scala中,包的作用域比起java来更加前后一致。Scala的包和其他作用域一样地支持嵌套,你可以访问上层作用域中的名称。例如:
package com {
package horstmann {
object Utils {
def percent of (value: Double, rate: Double) = value*rate/100
……….
}
package impatient {
class Employee
…….
def giveRaise( rate : Scala.Double) {
salary += Utils.percentOf( salary,rate )
}
}
}
}
注意Utils.percentOf修饰符。Utils类定义于父包,所有父包中的内容都在作用域内,因此没必要使用com.horstmann.Utils.precentOf。
包冲突
不过,这里有一个瑕疵。假定有如下代码:
package com {
package horstmann {
package impatient {
class Manager {
val suboardinates = new collection.mutable.ArrayBuffer[Employee]
…….
}
}
}
}
这里我们利用到一个特性,那就是scala包总是被引入。因此,collection包实际上指向的是scala.collection。现在假定有人加入了如下的包,可能位于另一个文件当中:
package com {
package horstmann {
package collection {
…….
}
}
}
这下Manager类将不再能通过编译。编译器尝试在com.horstmann.collection包中查找mutable成员未果。Manager类的本意是要使用顶级的scala包中的collection包,而不是随便什么存在于可访问作用域中的子包
包冲突方案
在Java中,这个问题不会发生,因为包名总是绝对的,从包层级的最顶端开始。但是在Scala中,包名是相对的,就像内部类的名称一样。内部类通常不会遇到这个问题,因为所有代码都在同一个文件当中,由负责该文件的人直接控制。但是包不一样,任何人都可以在任何时候向任何包添加内容。
解决方法之一是使用绝对包名,以_root_开始,例如:
val subordinates=new _root_.scala.collction.mutable.ArrayButfer[Employee]
另一种做法是使用"串联式"包语句,在后面会详细讲到
|
串联式包语句 |
包语句可以包含一个"串",或者说路径区段,例如:
package com.horstmann.impatient { // com和com.horstmann的成员在这里不可见
package people {
class Person
}
}
这样的包语句限定了可见的成员。现在com.horstmann.collection包不再能够以collection访问到了
|
文件顶部标记法 |
除了我们到目前为止看到的嵌套标记法外,你也可以在文件顶部使用package语句,不带花括号。例如:
package com.horstmann.impatient
package people
class Person
这等同于
package com.horstmann.impatient {
package people {
class Person
……
// 直到文件末尾
}
}
如果文件中的所有代码属于同一个包的话:这也是通常的情形,这是更好的做法。还需注意是:在上面的示例当中,文件的所有内容都属于com.horstmann.impatient.people,但com.horstmann.impatient包的内容是可见的,可以被直接引用
|
包对象 |
包可以包含类、对象和特质,但不能包含函数或变量的定义。很不幸,这是Java虚拟机的局限。把工具函数或常量添加到包而不是某个Utils对象,这是更加合理的做法。包对象的出现正是为了解决这个局限。每个包都可以有一个包对象。你需要在父包中定义它,且名称与子包一样。例如
package com.horstmann.impatient
package object people {
val defaultName="John Q. Public"
}
package people {
class Person {
var name=defaultName // 从包对象拿到的常置
}
…….
}
}
注意defaultName不需要加限定词,因为它位于同一个包内。在其他地方,这个常量可以用com.horstmann.impatient.people.defaultName访问到。在幕后,包对象被编译成带有静态方法和字段的JVM类,名为package.class,位于相应的包下。对应到本例中,就是com.horstmann.impatient.people.package,其中有一个静态字段defaultName。在JVM中,你可以使用package作为类名。对源文件使用相同的命名规则是好习惯,可以把包对象放到文件com/horstmann/impatient/people/package.scala。这样一来,任何人想要对包增加函数或变量的话,都可以以很容易地找到对应的包对象
|
包可见性 |
在Java中,没有被声明为public、private或protected的类成员在包含该类的包中可见。在Scala中,你可以通过修饰符达到同样的效果。以下方法在它自己的包中可见:
package com.horstmann.impatient.people
class Person {
private[people] def description="A person with name "+name
…….
}
你可以将可见度延展到上层包:
private[impatient] def description="A person with name "+name
|
引入 |
引入语句让你可以使用更短的名称而不是原来较长的名称。写法如下:
import java.awt.Color
这样一来,你就可以在代码中写Color而不是java.awt.Color了,这就是引入语句的唯一目的。如果你不介意长名称,你完全不需要使用引入。你也可以引入某个包的全部成员:
import java.awt._
这和Java中的通配符*一样。在Scala中,*是合法的标识符。你完全可以定义com.horstmann.*.people这样的包,但请别这样做。你还可以引入类或对象的所有成员:
import java.awt.Color._
val c1 =RED // Color.RED
val c2=decode("#ff0000") // Color.decode
这就象Java中的import static。Java程序员似乎挺害怕这种写法,但在Scala中这样的弓很常见。一旦你引入了某个包,你就可以用较短的名称访问其子包。例如:
import java.awt._
def handler(evt: event.ActionEvent) { // java.awt.event.ActionEvent
……….
}
event包是java.awt包的成员,因此引入语句把它也带进了作用域
|
任何地方都可以声明引入 |
在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部。import语句的效果一直延伸到包含该语句的块末尾。例如:
class Manager {
import scala.collection.mutable._
val subordinates = new ArrayBuffer[Employee]
}
这是个很有用的特性,尤其是对于通配引入而言。从多个源引入大量名称总是让人担心。事实上,有些Java程序员特别不喜欢通配引入,以至于从不使用这个特性,而是让IDE帮他们生成一长串引入语句。通过将引入放置在需要这些引入的地方,你可以大幅减少可能的名称冲突。
|
重命名和隐藏方法 |
重命名
如果你想要引人包中的几个成员,可以像这样使用选取器( selector):
import java.awt.Color.{ Color,Font }
选取器语法还允许你重命名选到的成员:
import java.util.{ HashMap=>JavaHashMap }
import scala.collection.mutable._
这样一来,JavaHashMap就是java.utiI.HashMap,而HashMap则对应scala.collection.mutable.HashMap。
隐藏方法
选取器HashMap =>_将隐藏某个成员而不是重命名它。这仅在你需要引入其他成员时有用:
import java.util.{HashMap=>_,_ }
import scala.collection.mutable._
现在,HashMap无二义地指向scala.collection.mutable.HashMap,因为java.util.HashMap被隐藏起来了
|
隐式引入 |
每个Scala程序都隐式地以如下代码开始:
import java.lang._
import scala._
import Predef._
和Java程序一样,java.lang总是被引入。接下来,scala包也被引入,不过方式有些特殊。不像所有其他引入,这个引入被允许可以覆盖之前的引入。举例来说,scala.StringBuilder覆盖java.lang.StringBuilder而不是与之冲突。最后,Predef对象被引入。它包含了相当多有用的函数,这些同样可以被放置在scala包对象中,不过Predef在Scala还没有加入包对象之前就存在了。
由于scala包默认被引入,对于那些以scala开头的包,你完全不需要写全这个前缀。例如:
collection.mutable.HashMap
上述代码和以下写法一样好:
scala.collection.mutable. HashMap
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【Sunddenly】。本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Scala学习(七)---包和引入的更多相关文章
- Scala学习七——包和引入
一.本章要点 包也可也可以像内部类那样嵌套 包路径不是绝对路径 包声明链x.y.z并不自动将中间包x和x.y变成可见 位于文件顶部不带花括号的包声明在整个文件范围内有效 包对象可以持有函数和变量 引入 ...
- Scala学习(七)练习
控制结构和函数 1. 编写示例程序,展示为什么 package com.horstmann.impatient 不同于 package com package horstmann package im ...
- Scala学习-02-方法
算数和操作符重载 所有的操作符都是方法. a + b 是一种缩写形式 : a .+ b “+”是方法名(操作符重载) ++和—— Scala中并没有“++”和“——”.需要使用“+=”和“-=” ...
- 快学scala-第七章 包和引入
知识点: 1. Scala.Java.C++的包的目的都是为了管理大型程序中的名称.与对象或类的定义不同,同一个包可以定义在多个文件当中.或者在同一个文件中,为多个包贡献内容. 2. Scala的包和 ...
- Scala学习(九)---文件和正则表达式
文件和正则表达式 摘要: 在本篇中,你将学习如何执行常用的文件处理任务,比如从文件中读取所有行或单词,或者读取包含数字的文件等.本篇的要点包括: 1. Source.fromFile(...).get ...
- 【大数据】Scala学习笔记
第 1 章 scala的概述1 1.1 学习sdala的原因 1 1.2 Scala语言诞生小故事 1 1.3 Scala 和 Java 以及 jvm 的关系分析图 2 1.4 Scala语言的特点 ...
- Scala学习——基础篇
[<快学Scala>笔记] 一.基础 1.变量val 标志符: 声明常量: 如,val answer = 1var 标志符:声明变量: 类型推断:变量的类型由scala根据初始化变量的表达 ...
- Scala学习笔记(一)数据类型
.类型参数化数组 val arrayString = Array[String](2); arrayString (0)="Hello"; arrayString (1)=&quo ...
- MyBatis学习七:spring和MyBatis整合
<\mybatis\day02\16mybatis和spring整合-sqlSessionFactory配置.avi;> MyBatis学习七:spring和MyBatis整合.逆向工程 ...
随机推荐
- spring使用BeanPostProcesor实现AOP源码分析
源码 AbstractApplicationContext#public void refresh() throws BeansException, IllegalStateException { f ...
- python 遇到的小坑
由于前端资源紧缺,我的后端系统迟迟等不来它的前端,没办法只好自己来写了.从html,js入门学起,然后照着vue.js的官方教程写了几个实例,从github上clone了一个不错的vue.js模版,填 ...
- 洗礼灵魂,修炼python(51)--爬虫篇—变色龙般的伪装
变色龙原理 变色龙这种动物想必大家都了解,它们会根据周遭环境的局势来改变自己的颜色,伪装自己. 那么爬虫有这种技能吗?当然是有的,先不着急说这个问题. 从上一篇开始,你有没有想过,站在网站管理的角度, ...
- 华硕200系主板完美兼容M.2安装Win7系统
虽然Windows 10系统的装机率正不断攀升,但经典的Windows 7依然有着大量的用户群体.特别是在我们中国, Windows 7依然是许许多多电脑用户的装机首选系统. 经久不衰的Windows ...
- 彻底卸载删除Win10易升,禁止再生
易升是微软推出的win10升级工具.用户可通过易升一键升级win10. 因为我的电脑已经是win10的系统,所以我也不需要升级.也不想升级,因为我从网上了解到升级后的系统反而没有升级前的好用. 微软的 ...
- 【PAT】B1036 跟奥巴马一起编程(15)(15 分
#include<stdio.h> int main() { int row,col; char c; scanf("%d %c",&col,&c); ...
- Docker容器学习与分享12
Docker多主机管理 之前在一台Centos7上安装了Docker,如果是在多台主机上都安装Docker,用手动安装的方法不光效率低下,而且有可能出错,所以可以使用Docker Machine进行多 ...
- Java并发编程(多线程)中的相关概念
众所周知,在Java的知识体系中,并发编程是非常重要的一环,也是面试中必问的题,一个好的Java程序员是必须对并发编程这块有所了解的. 并发必须知道的概念 在深入学习并发编程之前,我们需要了解几个基本 ...
- D - C Looooops POJ - 2115 欧几里德拓展
题意:就是看看for(; ;)多久停止. 最让我蛋疼的是1L和1LL的区别!让我足足wa了12发! 1L 是long类型的, 1LL为long long类型的! 思路: 这就是欧几里德扩展的标准式子了 ...
- CSS3系列教程:HSL 和HSL
使用CSS3 HSL声明同样是用来设置颜色的.下一个呢? HSLA? 是的,这个和RGBA的效果是一样的. HSL声明使用色调Hue(H).饱和度Saturation(s)和亮度Lightness(L ...