Java中关于package的总结(转载)
2014-05-05 11:20
267 查看
本文主要转载自以下两个链接
http://coolwinding.diandian.com/post/2011-02-17/19623018http://blog.sina.com.cn/s/blog_4acc2c05010005e1.html
由于大家对package的使用存在太多困惑,我在这里将自己对于package的使用的领悟进行一点总结:
package中所存放的文件
所有文件,不过一般分一下就分这三种
java程序源文件,扩展名为.java。
编译好的java类文件,扩展名为.class。
其他文件,其他任何文件,也称为resource
例如图片文件,xml文件,mp3文件,avi文件,文本文件……
package是什么
package好比java用来组织文件的一种虚拟文件系统。package把源代码.java文件,.class文件和其他文件有条理的进行 一个组织,以供java来使用。package是将文件组织在一颗类似unix,linux文件系统的树结构里面,它有一个根"/",然后从根开始有目录 和文件,目录中也还有文件和目录。package怎么实现的呢?
源代码的要求最严格,而一旦源代码自己声明了在哪个package路径之下,class也就有了自己在哪个package下面的信息,就是那句 程序开头的"package xx.xx.xx"。有人问,为什么要有这个信息,直接放目录结构里不就好了么?是啊,直接放目录中确实可以找到.class和.java,但是如果我要输出这个.class是属于哪个package的,该怎么办?所以我们需要在.class里面留一个package的信息。如果我们要区分同样名称为 A.class的类怎么办?所以我们需要在.class里面留一个package的信息。
.java文件是一个独立的编译单元,类似c++里面的cpp文件,但是它不需要.h文件,只要.java就足够了,一个.java文件里面可 以包含一个public的类,若干package类(package类特征是没有任何访问控制修饰),还有内隐类的话,则还可以包含若干 protected和private的类。每个类,都会在编译的时候生成一个独立的.class文件,所以.java和.class不是一对一,而是一对
多的关系,不过.java和public的类是一对一的。所有这些.class,都由这个.java开头的package语句来确定自己在package 中的位置。
package xx.bb.aa;
说明这个.java编译单元中的所有类都放到xx.bb.aa这个package里面。而对应的,必须把这个.java文件放在xx目录下bb 目录下的aa目录里面。如果一个.java文件没有任何package语句,那么这个.java里面的所有类都在package的"/"下面,也称之为 default
package。可以看出你一般从任何java教科书上写的第一个hello world程序的那个类是在defaultpackage里面的。有了package语句,情况就复杂一点了。这个编译单元.java必须放在 package名对应的目录之下。而生成的class文件也要放在对应的目录结构之下才能正常运作。
例如:
/* A.java */
package aaa.bbb.ccc;
public class A{
B b=new B();
}
/* B.java*/
package aaa.bbb.ccc;
public class B{}
编译时候怎么填参数呢?我根据package+文件名的格式来写,
javac aaa.bbb.ccc.A.java
漂亮吧?可惜不工作。非要使用合法的路径名才行:
javac aaa/bbb/ccc/A.java
(此处为自己补充的说明:虽然javac不能,但java aaa.bbb.ccc.A却是可以的。因为运行javac后,包路径已经被设置好了)
但是你发现生成的class丢失了目录结构,直接出现在当前目录下……
最好的方式是
javac -d bin aaa/bbb/ccc/A.java
这样就会在当前目录的bin目录下看到完整的目录结构以及放置妥当的class文件。
(补充自http://blog.sina.com.cn/s/blog_4acc2c05010005e1.html---package用法)
实际上,当你在编译一些有package语句的编译单元的时候,如果你使用的是命令行的话,应该使用-d参数让编译器自己生成目录结构,实际上你的.java就应该放在这种目录结构
之中。我举个非常简单的例子,有个人写了这么两个.java文件。
/* A.java */
package aaa.bbb.ccc;
public class A{
B b=new B();
}
/* B.java*/
package aaa.bbb.ccc;
public class B{}
然后这个人就把这两个文件就放在当前目录之下,然后javac A.java,
4000
然后傻眼。
说找不到B,怎么找不到呢?
为什么找不到呢,不是在一个package里面吗?
对,是在一个package里面,但是B.java必须放在当前目录/aaa/bbb/ccc下面才可用,
当javac编译A.java的时候,它发现当前所在的包是aaa.bbb.ccc,然后需要一个B类,
没有B.class,就要去找B.java,而B.java的package语句和自己所在目录结构不符,没法
使用,所以就傻眼了。
这个人就知道了把B.java放到当前目录/aaa/bbb/ccc里面,嘿,编译通过了。
没错,生成了A.class,但是A.class还是不可用的,因为它不在它应该在的地方。
我们又必须将它放到它应该在的地方,它才能好好运作。
那你说我把A.java也放在当前目录/aaa/bbb/ccc里面,然后
javac aaa.bbb.ccc.A.java
漂亮吧?
不行,为什么?因为javac接受的参数是一个文件系统的文件名,javac命令行中的参数
只能是一个完整的路径名。
那我把A.java放在当前目录/aaa/bbb/ccc里面,然后
javac aaa/bbb/ccc/A.java
这下好了吧,恩,差不多,但是生成的class还是直接丢在了源代码目录之下
最好是
javac -d bin aaa/bbb/ccc/A.java
这样就会在当前目录的bin目录下看到完整的目录结构以及放置妥当的class文件
===============================================================================
package与classpath不得不说的事
对于java来讲,所有需要的程序和资源都要以package的形式来组织和读取。那么classpath又是什么呢?
所有放到设定到classpath里面的东西就是package所包纳的资源。classpath的写法如同path,只是里面可以写的一般只 有zip文件、jar文件和目录。多个元素之间用当前系统路径分隔符间隔开了,linux上分隔符号是":",windows上是";"。 classpath在java里面是被一个叫做classloader的东西所使用的,classloader顾名思义,就是load
class用的,但它也可以load其它在package里面的东西。现在的java里面classloader是有阶层关系的,一般我们所常接触到的 CLASSPATH环境变量,javac,java的-cp,-classpath参数所给的classpath信息是被appclassloader所 使用的。而appclassloader其实是第三层的classloader,最高层的classloader叫做bootstrap classloader,它不是java写的classloader,而是c++写成的,第二层叫做extclassloader,默认包纳是
jre/lib/ext里面的classes目录和所有jar文件作为内容。第三层才是我们命令行参数,或者不用命令行参数,用系统环境变量指定 classpath的使用者app classloader,这是最基本的java se。如果是java ee,有了服务器,容器,还有更多层的classloader,他们在app classloader的更下面,例如tomcat的某web应用程序的web-inf/lib中的jar,zip和classes目录,是app之下好 几层的classloader使用的。
你可以建立自己的classloader,都在app classloader之下,实际上tomcat本身也是这样建立classloader的。分层的目的是为了安全,试想你加入搞了一个 classloader,从网络上读取class,而在里面写上格式化硬盘的代码,人家一读运行,那不就挂了,所以分层之后,首先从最高层读,没有再往下
找,找到就不着了。一般java所必须的rt.jar里面的若干class,是在bootstrap classloader启动的时候读入的,而jmf使用的几个jar,是在ext classloader里面读入的。也就是说,读入这些class的时候,我们的appclassloader还在娘胎里呢,所以你在CLASS PATH中指定rt.jar是完全愚蠢多余的。java绝对不会到这里找rt.jar,而bootstrapclassloader如果你不特别要修改, 它是常量,不需要你care。
(补充自http://blog.sina.com.cn/s/blog_4acc2c05010005e1.html---package用法)
讲了半天还是觉得不太清楚package的"/"到底在哪里,在当前目录吗?如果不知道package的"/"在哪里,那那些package中的文件在哪里就更无从得知了。
回答很简单,package的"/"在classpath中。
头痛了,package没有搞懂的,classpath一般也不会很懂。
没事,classpath说白了就是一堆path,这些该死的path有的指向一个目录,有的指向一个
文件(只能是zip或者jar两种,当然更保险的话还是用jar比较好)。
对于java虚拟机而言,它并不想过问这些path的八卦,它所做的是一视同仁!
它要的是所有这些path中的内容,对,对它而言,它不在乎内容是来自一个目录还是来自
一个文件,总而言之,所有的这些东西在他眼里都一样。就好像它空出一块地方,把所有
的文件解压,把所有的目录中的内容保留目录结构的送入相应位置,形成一套它自己感
兴趣的package组织方式。它要的就是这种方式来访问。
所以我可以在a.jar中有一个目录结构aaa/bbb/ccc/A.class,然后在b.jar中也有一个同样
的目录结构aaa/bbb/ccc/B.class。当我把这两个文件都放在classpath中的时候,
对虚拟机而言,这个A.class和这个B.class就是放在同一个package中的。
前面的那个实践也透视了这一点,实际上编译A.java的时候,是在classpath中寻找class
文件的,找不到,则会在sourcepath中寻找其源代码文件(不设定的话,sourcepath就是等
于classpath),当我们把B.java放在当前目录中合适的目录结构中的时候,它就会找到
这个文件并将它编译,然后进行使用。因为当前目录"."是在classpath中的。
原则就是,对java而言,它是忽略文件系统细节的,它要求的只是自己的classpath
中按照约定存放的资源。
(以上classpath对应的classloader是app classloader)
========================================================================================
import干吗用的?
import只是一种让你偷点懒少打字的方法,绝对不会影响你的classpath,这点你要好好记住,没有非用import不可的理由,用了 import也不会起到类似c里面嵌入某文件内容的效果,它只是一种省事的办法。不在classpath中的class,任你再import也无济于事。如果你不用import,你用ArrayList这个类,就需要写
java.util.ArrayList。
而用了import java.util.ArrayList;的话
以后代码中写ArrayList就可以了,省事。import可以使用通配符*,*代表某package下所有的class,不包括子目录。
import java.awt.*
不等于
import java.awt.*
import java.awt.event.*
如果你要简写java.awt.event下和java.awt下的类,你不能偷懒,两个都要import。
自己的补充:
那么,用 import 某个包时,该被导入的类源代码中必有 package 关键字吗?答案是不一定。拿文中的类A和类B来说,如果,它们在同一个路径层次上,即使B源代码开头没有package关键字,A.class依然可以搜索到位于同个文件夹中的B.class,编译和运行都没有问题。这是一个特殊情况。java将这样的文件自动看作是隶属于该目录的“默认包”之中,所以不需要包外import。
当然,如果A和B在不同的目录下或层次,则一定要使用package关键字才能import成功,编译和运行才不会报错。
换句话来说就是:如果一个java类不使用package,那么它就不能够被“包”外引用,即被其它不同包的java类import成功。这属于java“访问权限控制”机制的一种表现。
相关文章推荐
- Java中关于package的总结
- [转载]关于Java IO流学习总结
- Java 关于中文乱码处理的经验总结【转载】
- Java中关于package的总结[转]
- Java中关于package的总结
- Java 关于中文乱码处理的经验总结
- Java中关于try-catch-finally的总结
- java Thread 总结 转载
- 关于java中package使用的几点问题
- JAVA与C++::关于JNI中文字符串操作问题总结
- 关于Java Collections Framework的一些总结(2)
- 对一道面试题的总结与扩展思考(关于一笔画问题的数学分析)(转载)
- Java初始化理解与总结 转载
- Java多线程编程总结(转载)
- 自己关于java编程的部分知识点总结
- [转载]Java学习总结(Java源文件、JavaDoc文档)
- java语言中关于抽象类和接口的区别(面试经常问到,因此总结一下)
- 关于近期java研发工程师面试的一些总结
- 关于Java的二进制输入输出流的一点总结(有错误请指出)
- 关于Java日志框架总结