欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java中package的浅解

程序员文章站 2024-03-01 18:23:46
...

如今我们已经习惯了使用IDE来编写程序,IDE对java包有着良好的管理,给用户带来了很多方便,但同时用户也可能会对package的机制缺乏了解,下面则对package的机制进行分析。

环境: debian9 vim


首先我们了解一下代码组织,当编写一个java源代码文件时,此文件通常被称为编译单元,每个编译单元都必须有一个后缀名.java, 而在编译单元内则可以有一个public类,该类的名称必须与文件的名称相同(包括大小写,但不包括后缀名.java)。每个编译单元只能有一个public类,否则编译器就不会接受。如果在该编译单元之中还有额外的类的话,那么在包之外的世界是无法看到这些类的,因为它们不是public类,而且它们主要用来为主public类提供支持。类库实际上是一组类文件。其中每个文件都有一个public类,以及任意数量的非public类。因此每个文件都有一个构件。如果希望这些构件同属于一个群组,就可以使用关键词package

如果使用package语句,它必须是文件中除注释以外的第一句程序代码。在文件起始处写:

package xxx;

就表示你在声明该编译单元是名为xxx的类库的一部分。任意想要使用该名称的人都必须作出选择,指定全名或者与xxx结合使用关键词import。(请注意,java包的命名规则全部使用小写字母,包括中间的字也是如此。)

例如,假设文件的名称是MyClass.java,这就意味该文件中只有一个public类,该类的名称必须是MyClass

//: access/MyClass.java 文件目录
	package access;
	public class MyClass {
	//......
	}

现在,如果有人想用MyClass或者是access中的任何其他public类,就必须使用关键字import来使access中的名称可用。另一个选择是给出完整的名称:

//: test/QualifiedMyClass.java
	public class QualifiedMyClass {
		public static void main(String[] args) {
			access.MyClass m = new access.MyClass();
		}
	}

关键词import可以使它更简洁:

//: test/ImportedMyClass.java
	import access.*;
	public class ImportedMyClass {
		public static void main(String[] args) {
			MyClass m = new MyClass();
		}
	}

packageimport关键词允许做的,是将单一的全局名字空间分割开,使得无论多少人使用Internet以及java开始编写类,都不会出现名称名称冲突问题。

java程序运行并且需要加载.class文件的时候,需要确定.class文件在目录上所处的位置。

java解释器的运行过程如下:首先,找出环境变量CLASSPATH。CLASSPATH包含一个或多个目录,用作查找.class文件的根目录。从根目录开始,解释器获取包的名称并将每个句点替换为反斜杠(包名可以为xxx.yyy.zzz ……),以从CLASSPATH根中产生一个路径名称(于是package xxx.yyy.zzz就变成xxx/yyy/zzz或者xxx\yyy\zzz或者其他形式,取决于操作系统)。得到的路径会与CLASSPATH中的各个不同的项相连接,解释器就在这些目录里查找相关的.class文件。

例如,创建一个全局名称com.shallowinggg,然后再在其中创建一个名为access的类库,可以将该名称进一步划分,于是得到一个包的名称如下:

package com.shallowinggg.aceess;

现在这个包名可以作为下面文件的保护伞:

//: com/shallowinggg/access/Test.java
	package com.shallowinggg.access;
	public class Test {
		Test() {
			System.out.println("com.shallowinggg.aceess.Test");
		}
	}


这个文件被放在我的系统的子目录下:

/home/shallowinggg/com/shallowinggg/access

沿此路径看,就可以看到包的名称com.shallowinggg.access,此路径的第一部分将由环境变量CLASSPATH关照,在我的机器上是:

CLASSPATH=.:/home/shallowinggg

在使用jar文件时必须在类路径中将jar文件的实际名称写清楚,而不仅指明它所在位置的目录。因此对于一个名为grape.jar的jar文件,类路径应该是

CLASSPATH=.:/usr/local/java/grape.jar

一旦类路径得以正确建立,下面的文件就可以放于任何目录之下:

//: reusing/LibTest.java
import com.shallowinggg.aceess.*;
public class LibTest {
       public static void main(String[] args) {
             Testtest = new Test();
       }
}

output:

com.shallowinggg.access.Test

以上是对package的一些简单介绍。

参考资料:thinking in java

 

如果不使用package关键词,我们的文件虽未置于指定的package中,但是这些文件其实已经位于包中了:即未命名包,或称为默认包。

下面则是我在使用package时碰到的一些问题和相应的解决方法(可能存在问题)。

 

第一个问题:

java中package的浅解

从此处我们可以看到Test类在access.protectedTest包中,使用java Test运行就会报错。

解决:在执行一个在package中的类时,需要输入完整的类名,加上包名

 

第二个问题:

 java中package的浅解

我们进入上级目录access中,此时我们的Test1类与Protected类不再同一个包中(Test1处于access目录的默认包,Protected类则处于accees.ProtectedTest包中),此处编译Test1.java就会报错。原因是protected的访问权限是包访问权限,只能在同一个包中被访问,在包外就无法调用此方法了。

 

第三个问题:

java中package的浅解

java中package的浅解

Wan类处于reusing包中,Test类在reusing目录中,处于默认包。第一个错误由于未编译导致(操作失误。。。),真正的错误在于编译时产生的错误,无法访问Wan。

问题在于Test的位置正好也处于reusing下,我们将Test换一个目录再进行编译

java中package的浅解

此处问题和问题二一样,然后我们修改一下Wan类,增加一个public方法fun2用来测试

java中package的浅解

在最后一行我们可以看到能够成功运行了。

解决:如果一个类没有使用package管理,在使用默认包的情况下,此类如果导入package为同一目录的类,则会产生错误,所以要避免使用默认包的类导入在包管理下的类(包名与使用默认包的类路径相同情况下)。