Java的Package和Classpath
Package
在Java中,Package是用来包含一系相关实例的集合。这些相关联的实例包括:类、接口、异常、错误以及枚举。
Package主要有一些的几点作用:
Package可以处理名字冲突,在冲突的名字前加上包的名字,通过使用名字的全限定名来访问名字的时候,可以避免名字冲突。因为在不同的包之间,具有不同的包名,所以可以通过全限定名来区分不同包中同名的名字。Package的这种机制称为名字空间管理(Namespace Management)。
Package可以实现访问控制,在Java中,除了常用的
public
和private
这两个访问控制修饰符外,还包含了protected
和default
这两个访问控制修饰符,这两个修饰符都和Package相关。通过protected
修饰的实体,它的访问受限于同一个包和它的子类中。如果一个实体没有包含任何的访问控制修饰符,那么默认就是default
,它的访问受限于同一个包中。用于发布可重用的类的集合,通常会将这些类打包成JAR包的形式。
Package的名字约定
一个包的名字可以通过将互联网的域名反向后加上自己的项目名字产生。中间通过.
进行分隔。Package的名字采用小写的方式。(i.e. 如果一个人的域名是'abc.com',那么他可以将自己项目的包名写成 'com.abc.project')。
我们可能会看到在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
的子包。
例子
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
CLASSPATH
是一个环境变量,Java虚拟机和编译器会通过这个环境变量来查找java类和包的位置。
Java虚拟机查找类的方式
在讨论Java的CLASSPATH环境变量之前,先介绍下Java虚拟机是如何查找Class文件的。
java虚拟机,也就是java
命令,通过以下的顺序查找和加载java的class文件:
- Bootstrap classes - 构成java平台的class文件,包括rt.jar和一些其他的重要的jar文件
- Extension classes - java的扩展机制的class文件,这些class文件以jar的方式组织并存在于扩展目录中
- User classes - 开发者和第三方创建的class文件,这些class文件的位置通过
-classpath(-cp)
选项来指定,或者通过设置环境变量CLASSPATH
来指定。
Java虚拟机查找Bootstrap classes的方式
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路径。
Java虚拟机查找Extension classes的方式
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类是未定义的。
Java虚拟机查找User classes的方式
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查找类的一中方式。
Java虚拟机查找jar包中的类的方式
一个jar包文件通常包含一个称为manifest
的文件,这个文件包含了这个jar包中的内容。这个manifest文件可以定义一个称为JAR-class-path
的类路径,这个类路径可以用于扩展Java的类路径(前提是这个jar包被加载进来)。通过JAR-class-path
访问类的顺序定义如下:
- 一般情况下,在一个jar包中的所有class文件都是通过一个JAR-class-path入口引用的,在查找的时候也是以JAR-class-path入口在类路径中的先后顺序进行访问的。
- 如果JAR-class-path指向的jar包文件已经被查找过,那么这个jar包文件将不会被再次查找(这种优化可以提高效率,并且避免循环查找)。
- 如果一个jar包文件是作为一个扩展包安装的,那么这个jar包定义的JAR-class-path会被忽略。所有的在这个jar包中的类文件会被认为是SDK的一部分,或者已经被作为扩展包安装。
引用
http://docs.oracle.com/javase/7/docs/technotes/tools/findingclasses.html
http://www.ntu.edu.sg/home/ehchua/programming/java/J9c_PackageClasspath.html
Java的Package和Classpath的更多相关文章
- Java - 25 Java 包(package)
Java 包(package) 为了更好地组织类,Java提供了包机制,用于区别类名的命名空间. 包的作用 1 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用. 2 如同文件夹一样,包 ...
- Java实现Package编译和访问
Java实现Package编译和访问 说明 所有文件都是使用UTF-8编码来写的,请不要用Windows记事本随便打开 Test.java文件中注释的方法说明了该类是不能访问其方法的 文件目录树 bi ...
- Java学习笔记三十一:Java 包(package)
Java 包(package) 一:包的作用: 如果我们在使用eclipse等工具创建Java工程的时候,经常会创建包,那么,这个包是什么呢. 为了更好地组织类,Java 提供了包机制,用于区别类名的 ...
- Java中JAVA_HOME与CLASSPATH的解析(转)
很多人在初学Java的时候经常会被书中介绍的一堆环境变量的设置搞得头昏脑胀,很多书中都会在初装JDK的时候让他大家设置JAVA_HOME环境变量,在开发程序的时候设置CLASSPATH环境变量,而很多 ...
- java的环境变量classpath中加点号 ‘.’ 的作用
java的环境变量classpath中加点号 ‘.’ 的作用 “.”表示当前目录,就是编译或者执行程序时,你的.class文件所在的目录: 当找.class文件时,先去“.”路径下找,找不到的话,在去 ...
- java带package的编译
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "java -cp d:\\TEST com/ ...
- Java包package之间调用问题-cmd运行窗口编译运行
问题:在使用了java包机制(package)后,编译出现错误:找不到或无法加载主类 xxx 的错误提示信息(各种编译不通过) 先给演示结果: 编译:javac -d classes src/a/He ...
- Java学习笔记-包,classpath,import,jar
这里介绍Java的包,classpath,import和jar 包(package) 对类文件进行分类管理 给类提供多层命名空间 写在程序文件的第一行 类名的全称的是 包名.类名 包也是一种封装形式 ...
- 集成自动化的条形码功能到internet应用程序,网站或自定义Java应用程序的条码控件Java Barcode Package
Java Barcode Package控件是一款条码生成控件,包含所有的JavaBean,Applets,Servlets和类库可以使用于装有Java虚拟机的任何平台,包括Windows®, Lin ...
随机推荐
- dom事件与event对象总结
1 事件:就是文档或浏览器窗口中发生的一些特定的交互瞬间. tips:js和xhtml的交互是通过当用户或浏览器操作网页时发生的事件来处理的. 1.1 事件流:即事件的顺序. 事件 ...
- C# 进程和线程
一.进程和线程 进程是对一段静态指令序列的动态执行过程,是系统进行资源分配和调度的基本单位.与进程相关的信息包括进程的用户标志.正在执行的已经编译好的程序.程序和数据在存储器中的位置等.同一个进程有可 ...
- 多线程下的for循环问题
List<int> _ValueLis = new List<int>(); private void AddInt(int i) { _ValueLis.Add(i); } ...
- 轮播图适应代码jQ
(function(){ var i = 0; var time ; $('.page-size').html('1'); var obj = $('.xst-scroll>li'); var ...
- 修改加粗cmd和powershell命令行的中文字体
powershell 传教士 原创文章 2016-06-20 允许转载,但必须保留名字和出处,否则追究法律责任 ---[前言]--- 1 环境: win10 10586 powershell 5.0 ...
- JAVA 中文转GBK内码方法
不能谷歌,百度了很久,没有直接的转换方法,参考 byte[]数组与十六进制字符串与字符串的互相转换 http://blog.163.com/roadwalker@126/blog/static/113 ...
- golang实现随机数
package main import ( "fmt" "time" "math/rand" ) func main() { r := ra ...
- OpenCV中的矩阵操作
函数 Description 说明 cvAdd Elementwise addition of two arrays 两个数组对应元素的和 cvAddS Elementwise addition of ...
- JSTL标签库的使用
首先是四大标签库 核心 标签库 <%@ taglib uri="http://java.sun.com/jsp/jstl/core"%> 格式标签库 <%@ ta ...
- wp8开发笔记之应用程序真机发布调试
写在前面的话: 相信很多和我一样关注wp8动态以及已经开发了一些wp8应用程序的朋友们都遇到过这样的问题,写的程序在模拟器上进行调试总是显的没什么说服力,想拿真机进行实际测试, 该怎么办才好呢? 进行 ...