在Java中,Package是用来包含一系相关实例的集合。这些相关联的实例包括:类、接口、异常、错误以及枚举。html
Package主要有一些的几点做用:java
Package能够处理名字冲突,在冲突的名字前加上包的名字,经过使用名字的全限定名来访问名字的时候,能够避免名字冲突。由于在不一样的包之间,具备不一样的包名,因此能够经过全限定名来区分不一样包中同名的名字。Package的这种机制称为名字空间管理(Namespace Management)。bootstrap
Package能够实现访问控制,在Java中,除了经常使用的public
和private
这两个访问控制修饰符外,还包含了protected
和default
这两个访问控制修饰符,这两个修饰符都和Package相关。经过protected
修饰的实体,它的访问受限于同一个包和它的子类中。若是一个实体没有包含任何的访问控制修饰符,那么默认就是default
,它的访问受限于同一个包中。bash
用于发布可重用的类的集合,一般会将这些类打包成JAR包的形式。oracle
一个包的名字能够经过将互联网的域名反向后加上本身的项目名字产生。中间经过.
进行分隔。Package的名字采用小写的方式。(i.e. 若是一我的的域名是'abc.com',那么他能够将本身项目的包名写成 'com.abc.project')。ide
咱们可能会看到在Java官方提供的包中,包含了java
和javax
前缀的包名,这两个前缀分别用于官方提供的java包和java的扩展包。工具
Java中的包名和文件系统的目录结构之间是有联系的。同一个包中的实体,都被存储在同一个目录下,确切的说,这些实体被存储在经过包名肯定的子目录结构下。i.e.,假设存在一个包名为 com.abc.project
的包,那么这个包中的实体被存储在目录$BASE_DIR/com/abc/project
下,其中的$BASE_DIR
表示了包的根目录,也能够称为Java中的类路径。经过上面的例子,咱们能够发现,将包名中的.
转换为/
就是相应的子目录结构了。开发工具
上面提到的$BASE_DIR
能够存在于文件系统的任何位置,因此Java的编译器和虚拟机必须知道$BASE_DIR
的位置,才能够定位到须要的实体。对这个位置的查找是经过环境变量CLASSPATH
来实现的。CLASSPATH
是一个相似于PATH
的环境变量,只是CLASSPATH
是用于查找Java的类的位置的。优化
在Java中,没有子包的概念。i.e.,两个包java.awt
和java.awt.event
,这两个包具备相同的前缀。其中包java.awt
中的实体存储在路径$BASE_DIR\java\awt
下,而包java.awt.event
中的实体存储在路径$BASE_DIR\java\awt\event
下,这是两个独立的包,只是具备相同的前缀而已,因此java.awt.event
不是java.awt
的子包。ui
package com.yyy; public class Circle { private double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } }
咱们在./src/java/com/yyy
目录下建立了一个com.yyy
的包,而且在包中建立了一个Circle类。而后咱们须要将这个类的编译后的class文件存储在目录classes
目录下。
javac -d ./classes ./src/java/com/yyy/Circle.java
javac
命令会编译这个java文件,而后将编译后的class文件存储在classes/com/yyy
目录下,com/yyy
这个子目录会根据包名com.yyy
自动生成。在这里,咱们经过选项-d
来指定生成的类存放的位置的根目录。
下面,咱们使用上面建立的类对象:
import com.yyy.Circle; public class TestCircle { public static void main(String[] args) { Circle c = new Circle(1.23); System.out.println(c.getRadius()); } }
咱们在目录./test
下建立类TestCircle
,可是咱们不能直接编译这个类:
cd test javac TestCircle.java
上面的命令会报错,提示找不到类com.yyy.Circle
,因此咱们须要告诉编译器该类的位置。经过选项-cp(-classpath)
能够指定类路径的位置(这个路径是包所在的根目录,而不是包中类的目录。经过这个根目录,java会自动查找包中的类)。
javac -cp ./classes TestCircle.java
经过-cp
指定类路径之后,能够顺利编译经过了,可是若是咱们直接执行生成的class文件,仍是会出现问题:
java TestCircle
上面的命令会报错,提示找不到类com.yyy.Circle
,因此咱们须要告诉命令哪里能够找到这个类,跟上面同样,给出这个类所在的位置,也就是类路径:
java -cp ./classses TestCircle
上面的命令,看似没什么问题了,可是运行仍是会报错,可是此次提示找不到TestCircle类。这是由于java的CLASSPATH
若是没有被显式定义指定,那么默认值是当前目录,因此第一次没有报找不到TestCircle的错误。可是若是咱们显式更改CLASSPATH
的值(经过上面的-cp选项),那么就默认不会包含当前的目录,若是须要包含当前的目录,则须要显式指定。在CLASSPATH
中能够经过:
分隔不一样的路径。
java -cp .:./classes TestCircle
若是TestCircle.java
被定义在包com.abc
中,那么若是咱们在这个包的根目录下引用这个类,则须要使用这个类的全限定名:
//TestCircle.java和Circle.java的class文件都被放在classes目录下 javac -d classes -cp ./classes src/com/abc/TestCircle.java //咱们当前所在的目录是包的根目录,因此引用TestCircle的时候,须要使用全限定名 java -cp ./classes com.abc.TestCircle
CLASSPATH
是一个环境变量,Java虚拟机和编译器会经过这个环境变量来查找java类和包的位置。
在讨论Java的CLASSPATH环境变量以前,先介绍下Java虚拟机是如何查找Class文件的。
java虚拟机,也就是java
命令,经过如下的顺序查找和加载java的class文件:
-classpath(-cp)
选项来指定,或者经过设置环境变量CLASSPATH
来指定。Bootstrap classes是一些用于实现Java 2平台的class文件。Bootstrap classes包含在rt.jar和一些其余的jar文件中,这些jar文件放在jre/lib
目录下。这些包是经过bootstrap class路径指定的,这个路径值存储在sun.boot.class.path
这个系统属性中,这个系统属性应该是只读的,不该该直接修改。
通常状况下,bootstrap classes路径是不该该被从新修改的。Java的非标准选项-Xbootclasspath
,容许修改这个路径值来进行自定义定制核心class。
须要指出的是,实现Java 2 SDK的工具class文件并不和bootstrap class文件存放在一块儿。这些工具sdk存放在目录/lib/tools.jar
下。开发工具会在启动Java虚拟机的时候将这个jar包添加到user class路径中。然而,这个加强的user class路径只是用于执行这些工具,对于处理源代码的工具,如javac
和javadoc
,它们使用的是原始的class路径,而不是这个加强版本的class路径。
Extension classes是一些用于扩展Java平台的class文件。这些用于扩展Java平台的class文件被组织成jar包的形式,存储在jre/lib/ext
目录下。在这个目录下的jar文件会经过Java Extension Framework进行加载。在这个目录下的松散的class文件不会被查找,这些class文件必须是以jar/zip包的形式打包之后才能够被查找。这个扩展包存放的目录的位置是不能被修改的。
在目录jre/lib/ext
目录下若是存在多个jar文件,而且这些jar包中包含了同名的class文件,如:
smart-extension1_0.jar contains class smart.extension.Smart smart-extension1_1.jar contains class smart.extension.Smart
那么,具体加载上面哪一个smart.extension.Smart类是未定义的。
Uesr Classes是一些在java平台上建立的class文。Java虚拟机经过引用 user class path 来查找这些class文件的位置, user class path 是一个包含了class文件的目录、jar包和zip包的路径列表。
一个class文件拥有一个反映类的全限定名的子路径名,如:假设有一个名为com.mypackage.MyClass
的类,而且存放在目录/myClasses
下,那么目录myClasses
必须在 user class path 中,而且MyClass这个类的路径必须是/myClasses/com/mypackage/MyClass.class
。若是这个类被存储在myclasses.jar
这个jar包中,那么myclasses.jar
这个包必须在 user class path 中,而且这个类在jar包中的路径必须是com/mypackage/MyClass.class
。
用户类路径,也就是 user class path ,是以字符串的形式指定的,在Unix下经过:
进行分隔,而Win下使用;
进行分隔。Java虚拟机会将用户类路径中的字符串添加到java.class.path
系统属性中,这个属性的值有几种设置途径:
.
,表示当前目录CLASSPATH
的值,这个值会覆盖默认值。-cp / -classpath
选项指定的路径值,这个值会覆盖默认值和CLASSPATH
环境变量的值。-jar
选项指定的jar包的路径值,这个值会覆盖上面全部的值,若是这个选项被设置,那么全部的用户类必须经过jar包的形式指定。经过上面列出的规则,咱们能够知道,CLASSPATH
环境变量的值只是Java查找类的一中方式。
一个jar包文件一般包含一个称为manifest
的文件,这个文件包含了这个jar包中的内容。这个manifest文件能够定义一个称为JAR-class-path
的类路径,这个类路径能够用于扩展Java的类路径(前提是这个jar包被加载进来)。经过JAR-class-path
访问类的顺序定义以下:
http://docs.oracle.com/javase/7/docs/technotes/tools/findingclasses.html
http://www.ntu.edu.sg/home/ehchua/programming/java/J9c_PackageClasspath.html