从零认识Java Package
Java Package为何被设计?如果你没想过,我这里或许可以提供一种视角。
想象一下,作为一个语言的设计者,你一定会考虑一个问题:变量名的冲突。为了解决这个问题,C++引入了命名空间(namespace),而Java引入了package。
1.变量名冲突的情况
我们平常接触的所有软件编写,基本都是以文件为基本单位存储的,所以下面以文件为维度进行讨论。
- 同一文件内:在同一个文件中的变量名冲突,是完全可以通过编译去控制的,如果编译阶段检测到两个变量重复声明,可以报出错误给开发者。
- 不同文件间:当小A和小B分别编辑两个文件A.cpp和B.cpp时,就无法保证这两个文件中的变量名无重复,比如这两个文件中都存在
int b变量,则小A和小B都可以正常的分别编译A.cpp和B.cpp,所以在这里小A和小B都不会即时发现问题;但当小C引用了A.cpp和B.cpp,这两个文件合并编译的时候就会出错,可能这时小A和小B已经出去玩了。。。而这和单文件编译报错不同,这是两个不同的开发者开发的源码,小C最好不要乱改。
2.提出解决冲突的方案
现在摆在我们面前的,就是要解决小C的困扰,我们有以下两种方案:
- 把小A和小B叫回来,告诉他们他们再次声明变量的时候,需要互相通知,并且现在马上改一下他们造成的问题,这样用人工的方式避免掉变量名的冲突。
- 引入一种编译机制,编译文件的时候,给编译的文件内的变量名加上"文件名.",例如A.cpp里面的int b编译时标识成
int A.b,这样,只要保证文件不重名,就不用担心这两个文件中的所有变量会有重复了,至于文件名就交给OS的文件系统去判断重复不重复了。
这个方案的选择不是很难,正常人都会选第2种,但其实第2种方案还是有待完善的,不过我们的大方向走对了。
3.解决方案的优化
在变量名前面加上一个标识前缀(文件名.)确实是一种办法,我们暂时称为前缀法。但上面的方案只是会在编译阶段自动追加前缀,这样会引出一个问题:我如果在c.cpp中想引用A.cpp的int b变量,我又该如何?
所以,我们可以将前缀法运用在代码编写阶段,而不是编译阶段,什么意思呢?举个例子:
A.cpp编写的时候所有的变量都要加一个前缀(暂时约定为文件名),所以之前编写的int b应该改为
int A.b,注意,这里是在编辑时改为了int A.b,而不是编译时,要区分出这个时机。
这样,我便可以在C.cpp文件中,直接用A.b这个变量了。通过将前缀法转移到了编辑阶段,实现了多文件之间可以互相引用变量和方法而且不会引发变量名或方法名冲突了。
4.解决方案的实例
前缀法现在稍有成就了,解决了多文件之间的命名冲突,但还是有一些问题的。
前缀约定为"文件名."其实并不安全,因为我们知道同一目录下文件系统会要求不能存在重名的文件,但是不同目录下就可以,所以可能存在/Usr/A.cpp和/Dev/A.cpp两个文件合并编译的时候会发生错误。
同样,显而易见我们可以给出N种方案,这里给出三种:
我们不要把前缀和文件名划等号,我们可以给每一个文件的前缀指定不同的值,怎么做呢?在每份代码文件中用一个关键字(例如namespace)来标识这个文件的前缀,写法是这样的namespace devA或者namespace usrA,这样就给两个相同文件名的文件赋予了不同的前缀,而他们之间也可以互相引用。
我们还是把前缀和文件名绑在一起,但是这次狠一点,把文件夹也绑进来,什么意思呢?就是/Usr/A.cpp的变量都写成
int usr.A.b,这样其实前缀就和文件层次结合起来了,这样也可以完美解决问题。我们不要考虑前缀,文件内的前缀也不要,只要在跨文件引用的地方动态指定前缀就可以了,什么意思呢?就是/usr/A.cpp和/usr/A.cpp文件里变量
int b还是写int b,但是当C.cpp引用他们两个的时候,再他们指定前缀,看下面:
imort /usr/A.cpp userA;
imort /dev/A.cpp decA;
print userA.b -- 此处引用变量
print devA.b -- 此处引用变量
其实这三种也是分别对应的C++命名空间、Java Packge机制、Nodejs命名空间的解决方案的实例。
注意:C++ 命名空间和Java Package的区别在这里也可以看出来,在命名空间里只是每个文件中的namespace不同,和物理磁盘的文件名、路径无关;而Java Pakage是和文件层次绑在一起的,所以是和物理存储层次有关的。
4.package机制总结
既然我们的题目是Java Package,那么继续在第二种方案上继续往前。
对于Java的某个类,它唯一的标识符是package+类名,比方说com.test.Test,而我们编写的时候是通过package关键字,指明了Test类的的Package前缀为com.test。编译的时候,我们通过下面命令进行编译:
/ > javac Test.java
通过这行命令,在根目录下会生成一个Test.class文件,这时候大家注意到了,Test的Package编译完了并没有和文件系统的层次有对应关系,是的,确实没有,package的层次关系会指示出Test类应该所在的路径,以便可以让jvm找到。这里,你完全可以自己新建目录 /com/test/ 并将Test.class 放到这个目录里面,在回到根目录,执行 java com.test.Test,你会发现正常执行。
另外,在Test 里面的package已经指明层次关系了,其实是可以让javac自动生成对应的文件层次,并把Test.class放进去,免去手动移动的麻烦,就是javac后面加一个-d 目录名。
javac -d ./ com.test.Test
5.结尾
之前是对javac和package结合的地方很不明白,通过这么从零推导,现在明白多了,顺便分享给大家,希望对大家有帮助。
从零认识Java Package的更多相关文章
- JAVA package与import机制
JAVA package与import机制 http://files.cnblogs.com/files/misybing/JAVA-package-and-import.pdf import org ...
- java package(包)的用法
一般来说都用eclipse自动化图形工具搞定,我用的是ubuntu,所以需要自己打包引入. 什么是包? 这是对java源代码的组织和管理的一种方式,比如:当操作系统某个目录的文件非常多的时候,我们一般 ...
- Atitit.软件命名空间 包的命名统计 及命名表(2000个名称) 方案java package
Atitit.软件命名空间 包的命名统计 及命名表(2000个名称) 方案java package 1. 统计的lib jar 列表1 2. Code3 3. 常用包名按找字母排序(2000个)4 ...
- 从零讲Java,给你一条清晰地学习道路!该学什么就学什么!
从零讲JAVA ,给你一条 清晰地学习道路!该学什么就学什么! 1.计算机基础: 1.1数据机构基础: 主要学习:1. ...
- java package 命名空间
原文: http://www.studytonight.com/java/package-in-java.php 创建一个简单的maven 项目的命令是: mvn archetype:generat ...
- Java package 包的命名规范。
Java的包名都有小写单词组成,类名首字母大写:包的路径符合所开发的 系统模块的 定义,比如生产对生产,物资对物资,基础类对基础类.以便看了包名就明白是哪个模块,从而直接到对应包里找相应的实现. 由于 ...
- java package 包 学习笔记
编译命令示例: javac -d . Main.java 注:带参数-d自动建立文件目录, 只使用javac 则需要手工创建目录 把 class文件打包 jar命令 jar cvf T.jar *; ...
- 从零构建Java项目(Maven+SpringBoot+Git) #02 奥斯丁项目
前两天我说要写个项目来持续迭代,有好多小伙伴都表示支持和鼓励,项目的第一篇这不就来了么~我给项目取了个名字,英文名叫做:austin,中文名叫做:奥斯丁 名字倒没有什么特别的含义,我单纯觉得这个名字好 ...
- java package一些试验
目录如上图,当前目录下,b是文件夹, a是文件夹. B.java 源码如下: package b; import a.*; public class B{ public static void mai ...
随机推荐
- ps 替换背景以及调整尺寸
领导吩咐我修改她的图片背景,尺寸, 屁颠屁颠去弄,半小时后发现大学里学的 ps 忘差不多了,这里总结一下修改图片背景以及尺寸的基本操作. 1. 去除原背景 方法一: 选中魔术橡皮擦, 点击原图中背景, ...
- Django源码分析之程序执行入口分析
一般我们开启一个django项目,最简单的方法是进入project 目录,这时目录结构是这样的 然后我们执行python manage.py runserver,程序就开始执行了. 那django是如 ...
- JavaScript作用域,内部函数比参数优先级高
var x=0; f(); console.log(x); var f=function(){ x=1; } f(); console.log(x); function f(){ x=2; } f ...
- 关于js中的json对象,json串,数组之间相互转换
将json对象转换成string var loginUser = {username: username, password: password}//方式一 localStorage.setItem( ...
- mysql数据库表结构与表约束
表结构操作: 添加单列:alter table tb_name add [column] col_name 添加一列: alter table `sudty` add `aaa` int; 添加多列: ...
- metasploit魔鬼训练营(收集外围信息)
现在我们时空穿越,来到魔鬼训练营的主角身上,现在我们要训练,对V公司进行渗透测试,回想起总监说的情报收集 1,外围搜集,指的是自己假装是一个正常用户来搜集情报 我们开启msf用auxiliary/sc ...
- Maven(三)在Eclipse中使用Maven与Maven坐标
这一篇讲解一下在eclipse中使用maven,在一些高版本的eclipse中是自带maven插件的.所以这里就不在讲解怎么安装插件了. 接下来我们创建一个MavenFirst项目 一.在Eclips ...
- Timus Online Judge:ural:1006. Square Frames
原题链接:http://acm.timus.ru/problem.aspx?space=1&num=1006 看到题第一反应:这玩意怎么读入…… 本地的话因为是全角字符,会占两个位置,所以需要 ...
- How to find missing USB Records?
In my previously article "EnCase missed some USB activities in the evidence files", I ment ...
- 独立服务器 云主机、VPS以及虚拟主机三者之间的区别是什么?哪个更好?
https://www.zhihu.com/question/21442353#answer-2442764 云主机(如 EC2,[1] )和 VPS (如 Linode,[2])都是完整的操作系统( ...