java中的"包"机制

完全掌握java中的"包"机制

"包"机制是java中特有的,也是java中最基础的知识。一些初学java的朋友,通常象学其它语言一样从教材上copy一些程序来运行,可是却常常遇到莫名其妙的错误提示。这些问题事实上都出在对"包"的原理不够清楚。本文将就此问题进行深入阐述。

  一、为什么java中要有"包"的概念?

  以一言概之,java中"包"的引入的主要原因是java本身跨平台特性的需求。因为java中的所有的资源也是以文件方式组织,这其中主要包含大量的类文件需要组织管理。java中同样采用了目录树形结构。虽然各种常见操作系统平台对文件的管理都是以目录树的形式的组织,但是它们对目录的分隔表达方式不同,为了区别于各种平台,java中采用了"."来分隔目录。

  二、java中包结构和平台的衔接

  java中的资源存在于不同平台下时必然会有很大差异。因此跨平台的java包结构和平台之间必须通过一种方式来衔接到一起。事实上它们就是通过我们很熟悉的classpath的设置来衔接到一起的。举个例子:

  我在Windows2000环境下的classpath设置如下:

  classpath = d:\jdk1.4.2\lib\dt.jar; d:\cjm

java中的类的组织是"悬空"的,这样的话,它们可以随意放在任意平台下,但是要在该平台下正确找到一个类,则必须使用classpath来设置类所在目录的前面一部分(即区别于平台的部分)。在java中常常把一棵类树压缩成一个.jar文件,如图中的rt.jar,这并不影响对类的查找,在指定环境变量时可以指定.jar文件所在目录,也可以具体指明.jar的完全查找路径,即上例中的classpath中也可描述成:

  classpath = d:\jdk1.4.2\lib; d:\cjm

  当正确设置了平台下的classpath环境变量时,java跨平台的特性就体现出来了。即你在编写程序中,描述一个类时,就不用具体指明它的完整路径,而是仅仅指明java中的类路径就可以了,即指出图1中竖线右边的查找路径就可以了。这样的话,你编写的程序拿到任何平台下时,只需要根据类文件的存放目录来书写相应的classpath环境变量,而不用因为类的存放环境变化而修改程序。

  注意:java中对于某个类的查找是把classpath中的每一项逐一连接,当一个连接能够正确找到相关类后,便不再向后查找。

  三、正确使用"包"

  在使用包的过程中有很多需要注意的小细节,这里把常见的问题都列举如下:

  1、对类路径的设置通常有两种方法:

  i)在系统的环境变量中设置,设置方法依据平台而变;

  ii)以命令参数的形式来设置。

  如:javac -classpath d:\jdk1.4.2\lib d:\cjm\edu\test\TestFile.java

  java -classpath .;d:\jdk1.4.2\lib; d:\cjm  edu.test.TestFile

  注意:i)javac和java命令有很大区别,可以这样区分,javac是一个平台命令,它对具体的平台文件进行操作,要指明被编译的文件路径。而java是一个虚拟机命令,它对类操作,即对类的描述要用点分的描述形式,并且不能加扩展名,还要注意类名的大小写。

  ii)有一个很奇怪的问题,即javac命令后面的classpath默认包含当前目录(符合windows的习惯),可是在java命令后面的classpath却不包含当前目录,所以在它的classpath中一定不能忘了加上当前目录的描述,即加上"."。

  2、在java程序中对类路径的描述用"."分隔,而且也有当前目录的概念。如要运行图1中的TestFile必须指明为 edu.test.TestFile。但是如果在类TestFile中要调用和它在同一目录中的TestString,则不必指明目录前缀。

  3、在java程序中所有使用到的类都应该清楚的指明这个类的查找路径。一般有两种方法指明:

  i)在程序的开始使用import关键字指明。如类TestFile中要用到FileInputStream类,则在程序头中加入import java.io.FileReader; 或import java.io.*;

  ii)在程序中用到FileFileReader类处直接写完整路径,如: java.io.FileFileReader fin = new java.io.FileReader("filename");

  注意:java.lang包总是被默认导入的。

  4、类的目录结构一定要和类中第一句"包声明"一致。如类TestFile.class对应的.java文件的第一句必须包含:package edu.test;

  确保类的存放路径和类中指明的"包路径"一致的方法一般有两种:

  i)编写.java文件时存放的目录事先确定好,如TestFile.java就直接放在edu\test目录下,然后用下面的语句编译:

  javac  -classpath d:\jdk1.4.2\lib d:\cjm\edu\test\TestFile.java

当编译完成后,产生的TestFile.class文件会出现在编译命令中java文件的描述路径中。即出现在d:\test\edu\test中

  ii)通过-d参数的使用来编译程序。如使用下面的语句来编译:

  javac  -d  d:\cjm  d:\temp\TestFile.java

  将在-d后指定的目录d:\cjm下面自动按照packagek中指定的目录结构来创建目录,并且将产生的.class文件放在这个新建的目录下,即在d:\cjm下面建立\edu\test目录,然后产生的TestFile.class放在d:\cjm\edu\test目录下。

  5、为了便于工程发布,可以将自己的类树打成.jar文件。如将图1中的edu下面的所有类文件打成一个.jar文件,可以先转到d:\cjm目录,再用下面的命令:

  jar -cvf test.jar edu\

  这时会在d:\test下产生一个test.jar文件,此.jar文件中包含edu\下的完整目录结构和文件。使用这个.jar文件时,只需在classpath中指明.jar文件的存放路径即可。

  6、对其它资源的使用,如图标文件,文本等资源文件的使用必须要注意,查找资源文件不应从类文件所在的目录开始,而是应该从package指定的类路径的起点开始(图1中从edu所在目录开始)。如图1中看到的文本文件word.txt在resource下面,而类文件TestFile.class在edu\test下,在TestFile.class中要使用到resource中的word.txt,要按如下操作:

  fin= new FileReader("resource/word.txt");

  而不应该是:fin= new FileReader("../../resource/word.txt");

  四、举例

  本例用于统计一个文本文件中的单词数,注释中的编号对应前一节的编号:

// TestFile.java

package edu.test; // --------------------------------------- 4

import java.io.FileReader; // ------------------------------ 3

import java.io.LineNumberReader;

class TestFile{

public static void main(String []argv){

TestString ts = new TestString(); // ---------------- 2

FileReader fin;

LineNumberReader line = null;

int wordNum = 0;

try{

fin= new FileReader("resource/word.txt"); // ---- 6

line = new LineNumberReader(fin);

}catch(Exception e){

e.printStackTrace();

System.exit(0);

}

while(true){

try{

String temp = line.readLine();

wordNum += ts.CountWord(temp);

}catch(Exception e){

break;

}

}

try{

line.close();

}catch(Exception e){};

System.out.println("Word count is:" + wordNum);

}

}

// TestString.java

package edu.test;

import java.util.*;

class TestString {

int CountWord(String str){

StringTokenizer token = new StringTokenizer(str);

return token.countTokens();

}

}

  两个.java文件存放在d:\temp目录下,当前目录为d:\temp使用下面的命令进行编译:

  d:\temp>javac  -classpath d:\jdk1.4.2\lib  -d d:\test  *.java

  用下面的命令运行:

  // --------------------------------- 1

  d:\temp> java -classpath .;d:\jdk1.4.2\lib; d:\test\com  edu.test.TestFile

  如果需要打包的话,先转到d:\test,然后用下面命令:

  // --------------------------------- 5

  jar -cvf test.jar edu\

  这时可产生一个test.jar文件,可将此文件置于任何平台下使用。

时间: 2024-08-24 14:48:57

java中的"包"机制的相关文章

《Java中的包机制》

1 /* 2 包的机制:(1) 3 */ 4 package lee; 5 public class PackageTest 6 { 7 public void Test(int num) 8 { 9 System.out.println("num="+num); 10 } 11 } 12 13 //包的使用:(2) 14 package lee.sub; 15 public class SubPackageTest 16 { 17 public void sub(int x) 18

黑马程序员【java中的反射机制】

Java中的反射机制 ------- android培训.java培训.期待与您交流! ---------- java的反射机制是java的特性之一,反射机制是构建框架技术的基础所在,使用反射可以使程序更加灵活,避免将程序写死在代码里.相对于很多初学者只接触过java基础的人,反射还是一个很朦胧难懂的概念,下面我们就来说一下反射的一些应用. java反射机制是指在运行状态中,动态获取信息以及动态调用对象方法的功能.java反射有3个动态性质:1.运行时生成对象实例,2.运行期间调用发放,3.运行

JAVA中关于锁机制

本文转自 http://blog.csdn.net/yangzhijun_cau/article/details/6432216 一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中). 取到锁后,他就开始执行同步代码(被synchronized修饰的代码):线程执行完同步代码后马上就把锁还给同步对象,其他在锁

用简易例子讲Java中的回调机制

首先说点题外话.为什么要写这篇文章,因为在看J.U.C包的FutureTask源码的时候,有一个done()方法,这是个抽象方法,用户实现它之后,FutureTask会在执行完后调用这个方法.这就是回调机制,回调的思想就是: 类A调用类B的b方法 类B的b方法执行完毕主动调用类A的callback()方法 给出思想过于抽象,所以我会举出一个简单的实例(虽然简单,但是能说明问题),并总结Java实现回调的步骤. 实例基于知乎上一个解释什么是回调机制的回答. 描述:?一个顾客入住了一个酒店,酒店提供

Java中带包(创建及引用)的类的编译与调试

Java中带包(创建及引用)的类的编译与调试 java源程序的编译大家都知道,也就是cmd中到源文件所在目录下javac **.java即可,当程序中有包声明还能简简单单的直接javac **.java吗?答案当然是no,下面举个简单的例子证明一下直接javac **.java会怎么样. 如下:F:\javaweb2班\20160531目录下有A.java文件,注意源文件中有包声明 package mypack; public class A { String name; int age; pu

java中利用反射机制绕开编译器对泛型的类型限制

首先看下面这个例子 public static void main(String[] args) { ArrayList<Integer> al1 = new ArrayList<Integer>(); al1.add(1); ArrayList<String> al2 = new ArrayList<String>(); al2.add("hello"); //int型链表和string型链表,结果为true System.out.pr

Java中的异常处理机制

Java中的异常处理机制 示例 public class test { public static void main(String[] args) { // TODO Auto-generated method stub String s="hello"; int i=Integer.parseInt(s); } } 运行异常结果 在上述代码中Integer.parseInt表示把字符串类型转化成整数类型,同时Integer是Int的封装类:程序会报错,因为计算机没有办法把hello

Java中的包

以下内容引用自http://wiki.jikexueyuan.com/project/java/packages.html: 在Java中使用包是为了防止命名冲突,来控制访问,使得搜索/定位和类.接口.枚举和注释等的使用更为简单. 包可以被定义为一组相关的类型(类.接口.枚举和注释),提供访问保护和命名空间管理. 在Java中一些已经存在的包有: java.lang - 包含了基本类 java.io - 包含有输入,输出功能的类 程序员可以定义自己的包来包含各种类和接口等.把实现的相关类组织在一

图解JAVA中的类加载机制(详细版)

注:本文为作者整理和原创,如有转载,请注明出处. 上一篇博文,把JAVA中的Class文件格式用图形的方式画了一下,逻辑感觉清晰多了,同时,也为以后查阅的方便. Class文件只是一种静态格式的二进制流,它只有被虚拟机加载进内存解析之后才会生成真正的运行时的结构,因此,搞清楚类加载机制不但有助于我们加深理解Class文件中各个字段的含义,同时也有利于我们更深入的了解JAVA代码背后的暗流涌动.比如new关键字背后,虚拟机都做了什么?JAVA中的哪些操作会真正导致类被加载?哪些操作又会导致类被初始