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. sqlite ef6

    参考文章: http://www.cnblogs.com/adswads/p/3808549.html 用NUGET 引用 System.Data.SQLite.EF6  app.config 会有默 ...

  2. 安装配置Oracle 12c RAC

    http://www.lab128.com/rac12_installation_using_vb/article_text.html

  3. 如何实现VM框架中的数据绑定

    作者:佳杰 本文原创,转载请注明作者及出处 如何实现VM框架中的数据绑定 一:数据绑定概述 视图(view)和数据(model)之间的绑定 二:数据绑定目的 不用手动调用方法渲染视图,提高开发效率:统 ...

  4. 大话命令之--ss

    大话命令之-ss ss是Socket Statistics的缩写.顾名思义,ss命令可以用来获取socket统计信息,它可以显示和netstat类似的内容. 优势: (1)显示更多更详细的有关TCP和 ...

  5. 读书笔记《PHP与MySQL程序设计》一

    第1章 PHP概述 1.1  历史(PHP4.PHP5.PHP5.3.PHP6[未发布]) 1.2 一般语言特性(实用性.强大功能.可选择性.成本[开源]) 第2章 环境配置 2.1 安装的前提条件( ...

  6. canvas图像处理汇总

    一.canvas的情况 canvas自从出来了之后,在前端的图像处理上面提供了各种各样的遍历,虽然很多的操作其实都是要应用到算法的,但是这个也给前端提供了很多的可能性,其中最终要的一个canvas函数 ...

  7. bzoj 1084;vijos 1191 [SCOI2005] 最大子矩阵

    Description 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. Input 第一行为n,m,k(1≤n≤100,1≤m≤2 ...

  8. HDU2988-Dark roads,HDU1233-还是畅通工程-最小生成树

    最小生成树: 中文名 最小生成树 外文名 Minimum Spanning Tree,MST 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的 ...

  9. 强连通分量&hdu_1269&Codeforce 369D

    强连通分量 标签: 图论 算法介绍 还记得割点割边算法吗.回顾一下,tarjan算法,dfs过程中记录当前点的时间戳,并通过它的子节点的low值更新它的low,low值是这个点不通过它的父亲节点最远可 ...

  10. Shell菜单脚本

    今天在这儿给大家分享一个我简单编写的Shell菜单脚本,傻瓜式的人机交互,人人都可以操作linux. #!/bin/sh #Shell菜单演示 function menu () { cat <& ...