1、
我们用import 关键字导入一个完整的库时,就会获得“包”(Package)。例如:
import java.util.*;
它的作用是导入完整的实用工具(Utility)库,该库属于标准Java 开发工具包的一部分。由于Vector 位于
java.util 里,所以现在要么指定完整名称“java.util.Vector”(可省略import 语句),要么简单地指定
一个“Vector”(因为import 是默认的)。
若想导入单独一个类,可在import 语句里指定那个类的名字:
import java.util.Vector;
现在,我们可以自由地使用Vector。然而,java.util 中的其他任何类仍是不可使用的。
之所以要进行这样的导入,是为了提供一种特殊的机制,以便管理“命名空间”(Name Space)。我们所有
类成员的名字相互间都会隔离起来。位于类A 内的一个方法f()不会与位于类B 内的、拥有相同“签名”
(自变量列表)的f()发生冲突。但类名会不会冲突呢?假设创建一个stack 类,将它安装到已有一个stack
类(由其他人编写)的机器上,这时会出现什么情况呢?对于因特网中的Java 应用,这种情况会在用户毫不
知晓的时候发生,因为类会在运行一个Java 程序的时候自动下载。
正是由于存在名字潜在的冲突,所以特别有必要对Java 中的命名空间进行完整的控制,而且需要创建一个完
全独一无二的名字,无论因特网存在什么样的限制。
迄今为止,本书的大多数例子都仅存在于单个文件中,而且设计成局部(本地)使用,没有同包名发生冲突
(在这种情况下,类名置于“默认包”内)。这是一种有效的做法,而且考虑到问题的简化,本书剩下的部
分也将尽可能地采用它。然而,若计划创建一个“对因特网友好”或者说“适合在因特网使用”的程序,必
须考虑如何防止类名的重复。
为Java 创建一个源码文件的时候,它通常叫作一个“编辑单元”(有时也叫作“翻译单元”)。每个编译单
元都必须有一个以.java 结尾的名字。而且在编译单元的内部,可以有一个公共(public)类,它必须拥有
与文件相同的名字(包括大小写形式,但排除.java 文件扩展名)。如果不这样做,编译器就会报告出错。
每个编译单元内都只能有一个public 类(同样地,否则编译器会报告出错)。那个编译单元剩下的类(如果
有的话)可在那个包外面的世界面前隐藏起来,因为它们并非“公共”的(非public),而且它们由用于主编译一个.java 文件时,我们会获得一个名字完全相同的输出文件;但对于.java 文件中的每个类,它们都有
一个.class 扩展名。因此,我们最终从少量的.java 文件里有可能获得数量众多的.class 文件。如以前用一
种汇编语言写过程序,那么可能已习惯编译器先分割出一种过渡形式(通常是一个.obj 文件),再用一个链
接器将其与其他东西封装到一起(生成一个可执行文件),或者与一个库封装到一起(生成一个库)。但那
并不是Java 的工作方式。一个有效的程序就是一系列.class 文件,它们可以封装和压缩到一个JAR 文件里
(使用Java 1.1 提供的jar 工具)。Java 解释器负责对这些文件的寻找、装载和解释(注释①)。
①:Java 并没有强制一定要使用解释器。一些固有代码的Java 编译器可生成单独的可执行文件。
“库”也由一系列类文件构成。每个文件都有一个public 类(并没强迫使用一个public 类,但这种情况最
很典型的),所以每个文件都有一个组件。如果想将所有这些组件(它们在各自独立的.java 和.class 文件
里)都归纳到一起,那么package 关键字就可以发挥作用)。
若在一个文件的开头使用下述代码:
package mypackage;
那么package 语句必须作为文件的第一个非注释语句出现。该语句的作用是指出这个编译单元属于名为
mypackage 的一个库的一部分。或者换句话说,它表明这个编译单元内的public 类名位于mypackage 这个名
字的下面。如果其他人想使用这个名字,要么指出完整的名字,要么与mypackage 联合使用import 关键字
(使用前面给出的选项)。注意根据Java 包(封装)的约定,名字内的所有字母都应小写,甚至那些中间单
词亦要如此。
例如,假定文件名是MyClass.java。它意味着在那个文件有一个、而且只能有一个public 类。而且那个类
的名字必须是MyClass(包括大小写形式):
package mypackage;
public class MyClass {
// . . .
现在,如果有人想使用MyClass,或者想使用mypackage 内的其他任何public 类,他们必须用import 关键
字激活mypackage 内的名字,使它们能够使用。另一个办法则是指定完整的名称:
mypackage.MyClass m = new mypackage.MyClass();
import 关键字则可将其变得简洁得多:
import mypackage.*;
// . . .
MyClass m = new MyClass();
作为一名库设计者,一定要记住package 和import 关键字允许我们做的事情就是分割单个全局命名空间,保
证我们不会遇到名字的冲突——无论有多少人使用因特网,也无论多少人用Java 编写自己的类。

解决方案 »

  1.   

    2、
    大家或许已注意到这样一个事实:由于一个包永远不会真的“封装”到单独一个文件里面,它可由多
    个.class 文件构成,所以局面可能稍微有些混乱。为避免这个问题,最合理的一种做法就是将某个特定包使
    用的所有.class 文件都置入单个目录里。也就是说,我们要利用操作系统的分级文件结构避免出现混乱局
    面。这正是Java 所采取的方法。
    它同时也解决了另两个问题:创建独一无二的包名以及找出那些可能深藏于目录结构某处的类。正如我们在
    第2 章讲述的那样,为达到这个目的,需要将.class 文件的位置路径编码到package 的名字里。但根据约
    定,编译器强迫package 名的第一部分是类创建者的因特网域名。由于因特网域名肯定是独一无二的(由
    InterNIC 保证——注释②,它控制着域名的分配),所以假如按这一约定行事,package 的名称就肯定不会
    重复,所以永远不会遇到名称冲突的问题。换句话说,除非将自己的域名转让给其他人,而且对方也按照相
    同的路径名编写Java 代码,否则名字的冲突是永远不会出现的。当然,如果你没有自己的域名,那么必须创
    125
    造一个非常生僻的包名(例如自己的英文姓名),以便尽最大可能创建一个独一无二的包名。如决定发行自
    己的Java 代码,那么强烈推荐去申请自己的域名,它所需的费用是非常低廉的。
    ②:ftp://ftp.internic.net
    这个技巧的另一部分是将package 名解析成自己机器上的一个目录。这样一来,Java 程序运行并需要装
    载.class 文件的时候(这是动态进行的,在程序需要创建属于那个类的一个对象,或者首次访问那个类的一
    个static 成员时),它就可以找到.class 文件驻留的那个目录。
    Java 解释器的工作程序如下:首先,它找到环境变量CLASSPATH(将Java 或者具有Java 解释能力的工具—
    —如浏览器——安装到机器中时,通过操作系统进行设定)。CLASSPATH 包含了一个或多个目录,它们作为
    一种特殊的“根”使用,从这里展开对.class 文件的搜索。从那个根开始,解释器会寻找包名,并将每个点
    号(句点)替换成一个斜杠,从而生成从CLASSPATH 根开始的一个路径名(所以package foo.bar.baz 会变
    成foo\bar\baz 或者foo/bar/baz;具体是正斜杠还是反斜杠由操作系统决定)。随后将它们连接到一起,
    成为CLASSPATH 内的各个条目(入口)。以后搜索.class 文件时,就可从这些地方开始查找与准备创建的类
    名对应的名字。此外,它也会搜索一些标准目录——这些目录与Java 解释器驻留的地方有关。
    为进一步理解这个问题,下面以我自己的域名为例,它是bruceeckel.com。将其反转过来后,
    com.bruceeckel 就为我的类创建了独一无二的全局名称(com,edu,org,net 等扩展名以前在Java 包中都
    是大写的,但自Java 1.2 以来,这种情况已发生了变化。现在整个包名都是小写的)。由于决定创建一个名
    为util 的库,我可以进一步地分割它,所以最后得到的包名如下:
    package com.bruceeckel.util;
    现在,可将这个包名作为下述两个文件的“命名空间”使用:
    //: Vector.java
    // Creating a package
    package com.bruceeckel.util;
    public class Vector {
    public Vector() {
    System.out.println(
    "com.bruceeckel.util.Vector");
    }
    } ///:~
    创建自己的包时,要求package 语句必须是文件中的第一个“非注释”代码。第二个文件表面看起来是类似
    的:
    //: List.java
    // Creating a package
    package com.bruceeckel.util;
    public class List {
    public List() {
    System.out.println(
    "com.bruceeckel.util.List");
    }
    } ///:~
    这两个文件都置于我自己系统的一个子目录中:
    C:\DOC\JavaT\com\bruceeckel\util
    若通过它往回走,就会发现包名com.bruceeckel.util,但路径的第一部分又是什么呢?这是由CLASSPATH
    环境变量决定的。在我的机器上,它是:
    CLASSPATH=.;D:\JAVA \LIB;C:\DOC\JavaT
    可以看出,CLASSPATH 里能包含大量备用的搜索路径。然而,使用JAR 文件时要注意一个问题:必须将JAR
    文件的名字置于类路径里,而不仅仅是它所在的路径。所以对一个名为grape.jar 的JAR 文件来说,我们的
    类路径需要包括:
    CLASSPATH=.;D:\JAVA \LIB;C:\flavors\grape.jar
    正确设置好类路径后,可将下面这个文件置于任何目录里(若在执行该程序时遇到麻烦,请参见第3 章的
    3.1.2 小节“赋值”):
    //: LibTest.java
    // Uses the library
    package c05;
    import com.bruceeckel.util.*;
    public class LibTest {
    public static void main(String[] args) {
    Vector v = new Vector();
    List l = new List();
    }
    } ///:~
    编译器遇到import 语句后,它会搜索由CLASSPATH 指定的目录,查找子目录com\bruceeckel\util,然后查
    找名称适当的已编译文件(对于Vector 是Vector.class,对于List 则是List.class)。注意Vector 和
    List 内无论类还是需要的方法都必须设为public。
    1. 自动编译
    为导入的类首次创建一个对象时(或者访问一个类的static 成员时),编译器会在适当的目录里寻找同名
    的.class 文件(所以如果创建类X 的一个对象,就应该是X.class)。若只发现X.class,它就是必须使用
    的那一个类。然而,如果它在相同的目录中还发现了一个X.java,编译器就会比较两个文件的日期标记。如
    果X.java 比X.class 新,就会自动编译X.java,生成一个最新的X.class。
    对于一个特定的类,或在与它同名的.java 文件中没有找到它,就会对那个类采取上述的处理。
    2. 冲突
    若通过*导入了两个库,而且它们包括相同的名字,这时会出现什么情况呢?例如,假定一个程序使用了下述
    导入语句:
    import com.bruceeckel.util.*;
    import java.util.*;
    由于java.util.*也包含了一个Vector 类,所以这会造成潜在的冲突。然而,只要冲突并不真的发生,那么
    就不会产生任何问题——这当然是最理想的情况,因为否则的话,就需要进行大量编程工作,防范那些可能
    可能永远也不会发生的冲突。
    如现在试着生成一个Vector,就肯定会发生冲突。如下所示:
    Vector v = new Vector();
    它引用的到底是哪个Vector 类呢?编译器对这个问题没有答案,读者也不可能知道。所以编译器会报告一个
    错误,强迫我们进行明确的说明。例如,假设我想使用标准的Java Vector,那么必须象下面这样编程:
    java.util.Vector v = new java.util.Vector();
    由于它(与CLASSPATH 一起)完整指定了那个Vector 的位置,所以不再需要import java.util.*语句,除
    非还想使用来自java.util 的其他东西。
      

  2.   

    包就是对一些类的封装.shuneng() ( ) 说的对
      

  3.   

    既然说到包 就不能不说到类
    既然说到类 就不能不提OOP
    Java是面向对象的语言 她里面的机制也就符合面向对象的机制
    面向对象 简单点说 就是把程序里的组件看成是活的 你可以把一个
    class比喻成一个美女 那么这个美女是不是应该有个国籍啊(假设不同的国家说不同的语言 彼此并不了解对方的语言)那这个国籍就是一个包
    那这个美女要是想和别人语言交流 她只会说自己国家的语言 要是别的国家的人想和她聊天
    那是无法实现的 这就是所谓的类与类之间的交流 或者是参数的传递。
    :)