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的困扰,我们有以下两种方案:

  1. 把小A和小B叫回来,告诉他们他们再次声明变量的时候,需要互相通知,并且现在马上改一下他们造成的问题,这样用人工的方式避免掉变量名的冲突。
  2. 引入一种编译机制,编译文件的时候,给编译的文件内的变量名加上"文件名.",例如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种方案,这里给出三种:

  1. 我们不要把前缀和文件名划等号,我们可以给每一个文件的前缀指定不同的值,怎么做呢?在每份代码文件中用一个关键字(例如namespace)来标识这个文件的前缀,写法是这样的namespace devA或者namespace usrA,这样就给两个相同文件名的文件赋予了不同的前缀,而他们之间也可以互相引用。

  2. 我们还是把前缀和文件名绑在一起,但是这次狠一点,把文件夹也绑进来,什么意思呢?就是/Usr/A.cpp的变量都写成int usr.A.b,这样其实前缀就和文件层次结合起来了,这样也可以完美解决问题。

  3. 我们不要考虑前缀,文件内的前缀也不要,只要在跨文件引用的地方动态指定前缀就可以了,什么意思呢?就是/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的更多相关文章

  1. JAVA package与import机制

    JAVA package与import机制 http://files.cnblogs.com/files/misybing/JAVA-package-and-import.pdf import org ...

  2. java package(包)的用法

    一般来说都用eclipse自动化图形工具搞定,我用的是ubuntu,所以需要自己打包引入. 什么是包? 这是对java源代码的组织和管理的一种方式,比如:当操作系统某个目录的文件非常多的时候,我们一般 ...

  3. Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package

    Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package 1. 统计的lib jar 列表1 2. Code3 3. 常用包名按找字母排序(2000个)4 ...

  4. 从零讲Java,给你一条清晰地学习道路!该学什么就学什么!

                                             从零讲JAVA ,给你一条 清晰地学习道路!该学什么就学什么! 1.计算机基础: 1.1数据机构基础: 主要学习:1. ...

  5. java package 命名空间

    原文: http://www.studytonight.com/java/package-in-java.php 创建一个简单的maven 项目的命令是: mvn  archetype:generat ...

  6. Java package 包的命名规范。

    Java的包名都有小写单词组成,类名首字母大写:包的路径符合所开发的 系统模块的 定义,比如生产对生产,物资对物资,基础类对基础类.以便看了包名就明白是哪个模块,从而直接到对应包里找相应的实现. 由于 ...

  7. java package 包 学习笔记

    编译命令示例: javac -d . Main.java 注:带参数-d自动建立文件目录, 只使用javac 则需要手工创建目录 把 class文件打包 jar命令 jar cvf T.jar *; ...

  8. 从零构建Java项目(Maven+SpringBoot+Git) #02 奥斯丁项目

    前两天我说要写个项目来持续迭代,有好多小伙伴都表示支持和鼓励,项目的第一篇这不就来了么~我给项目取了个名字,英文名叫做:austin,中文名叫做:奥斯丁 名字倒没有什么特别的含义,我单纯觉得这个名字好 ...

  9. java package一些试验

    目录如上图,当前目录下,b是文件夹, a是文件夹. B.java 源码如下: package b; import a.*; public class B{ public static void mai ...

随机推荐

  1. DirectSound---输出设备基本操作(枚举、查询等)

    DirectSound是DirectX组件之一,提供了对音频设备的捕获和播放能力,同时它也是唯一几个支持Xp系统的音频技术之一. DirectSound主要有以下特点: 优点: 播放音频低延迟. 硬件 ...

  2. 利用.Net自带的票据完成BaseController的未登陆自动跳转到登陆页功能

    一:定义票据中要记录的字段类 /// <summary> /// 用户存在于浏览器端的身份票据(非持久) /// 非持久 FormsAuthenticationTicket 的isPers ...

  3. [译]Python作为一种编程语言有多强大?

    Quora上有个问题:Python作为一种编程语言有多强大? 以下是Patrycja Okowicka的回答 说实话,Python是一门强大的语言,几乎所有东西都可以用Python创建!这就是为什么它 ...

  4. LVS集群之NAT模式实例(3)

    LVS集群NAT模式实例 1. 实验拓扑图 DS 必须有两块网卡,需要在上面做NAT. 2. 实验环境 3台CentOS6.4 64bit的服务器. 类型 IP DR eth0:10.20.73.20 ...

  5. HTML基础知识(常见元素、列表、链接元素、图片元素)

    1.HTML有关概念 全称: Hyper Text Markup Language(超文本标记语言) 其文件扩展名为".html"或".htm" * 超文本 - ...

  6. CCNA笔记(2)

    CCNA第一天笔记:何为因特网?答:因特网,是连接各台pc与终端设备,正是因为有了因特网,我们才能与全世界交流,玩在线游戏,在线学习.因特网给我们教育带来什么方便?答:没有了地域的阻止,可以在线学习, ...

  7. JDBC(二)之JDBC处理CLOB和BLOB及事务与数据库元数据获取

    前面大概介绍了JDBC连接数据库的过程,以及怎么操作数据库,今天给大家分享JDBC怎么处理CLOB和BLOB存储图片的事情,以及JDBC怎么去处理事务.怎么在插入数据的时候生成主键返回值 一.JDBC ...

  8. MATLAB学习笔记

    魔方矩阵(magic(阶数)) 魔方矩阵又称幻方,是有相同的行数和列数,并在每行每列.对角线上的和都相等的矩阵.魔方矩阵中的每个元素不能相同.你能构造任何大小(除了2x2)的魔方矩阵. 希尔伯特矩阵( ...

  9. HDU5447 Good Numbers

    http://acm.hdu.edu.cn/showproblem.php?pid=5447 网上好像只找到java的题解,写完就发一下c++代码咯,顺便纪念一下+存个int128板子 做法可以看tj ...

  10. c语言中标识符的作用域

    1.代码块作用域(block scope) 位于一对花括号之间的所有语句称为一个代码块,在代码块的开始位置声明的标识符具有代码块作用域,表示它们可以被这个代码中的所有语句访问.函数定义的形式参数在函数 ...