package的用法

来源:互联网 发布:中信期货交易软件 编辑:程序博客网 时间:2024/06/02 07:03
例如声明一个名为pack1的包名,package pack1;好了下面我们就利用范例来说明package的使用方法,及其编译运行的方法。

例一

假设在d盘下的新建一个文件夹(pack1),在pack1文件夹内包含两个java程序一个是Showmethod.java和Testshow.java;
Showmethod.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
packagepack1;//在这里把Showmethod类纳入到pack1包内
classShowmethod{
publicvoidshow(){
System.out.println("I'mashowmethod()ofShowmethodclass");
}
}
Testshow.java;
packagepack1;//在这里把Testshow类也纳入到pack1包内
publicclassTestshow{
publicstaticvoidmain(Stringargs[]){
Showmethodsm=newShowmethod();
sm.show();
}
}

例二

访问不在同一个包内的类,
在D盘分别建立pack1,pack2两个目录,
建立好之后将Showmethod.java放到pack1包内,
Showmethod.java的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
packagepack1;
publicclassShowmethod{
publicvoidshow(){
System.out.println("I'mashowmethod()ofShowmethodclass");
}
}
将Testshow.java放到pack2包内
Testshow.java的代码如下:
packagepack2;
publicclassTestshow{
publicstaticvoidmain(Stringargs[]){
pack1.Showmethodsm=newpack1.Showmethod();
sm.show();
}
}
由于此类需要调用位于pack1包中的Showmethod类的show方法,所以这里pack1.Showmethod sm=new pack1.Showmethod();这样写,还可以使用import 语句将pack1包内的Showmethod方法导入进来,这样这个地方pack1.Showmethod sm=new pack1.Showmethod();所以可以这样写Showmethod sm=new Showmethod()。

编译指南

编辑
编译这两个位于同一个包内的java程序
1:javac pack1\Showmethod.java
2:javac pack1\Testshow.java
这就是编译的方法 pack1是包名,包名后面跟的就是我们要编译的那个类名,编译好后pack1目录下会生成两个class文件,
运行方法:
java pack1.Testshow
注意运行时要指出包名,包名后有一个点"."然后是类名。
在访问不同 package里的类时,被访问的类必须被声明为public(就是公有类型的),否则在编译会报告错误。
编译方法"
1javac pack1\Showmethod.java
2: javac pack2\Testshow.java
编译好之后pack1,pack2目录下会分别产生一个.class文件,
运行方法:
java pack2.Testshow
使用import导入package。
————————————————————————————————————————
我的一点想法:
Java中的类按照package来进行存放和管理。类似于linux系统的目录树,好比java用来组织文件的虚拟文件系统;而.java源文件则是实体文件系统,因此它的编译要严格按照目录结构来进行,比如我的java工作目录为D:\workspace,在workspace下建立了名字为chapter的包,其中1.java在chapter包里面,则cd workspace后,输入javac 1.java会报错找不到文件,javac chapter\1.java则会编译成功,同样cd chapter; javac 1.java 也会成功。这印证了在编译时必须严格按照木结构以使得编译器能够找到.java文件的位置。
而.class文件的运行则是按照package规定的虚拟目录结构来管理的。比如上面编译成功的1.class文件会在chapter中生成,cd chapter进去chapter目录后,输入java 1,报错找不到主类,而输入java chapter.1则会成功运行(前提是D:\workspace已经设置环境变量加入类路径),同样在workspace目录下输入java chapter.1也会成功运行。
假如workspace下有两个文件1.java和2.java,其中2.java含有主类,且它使用了1.java定义的类,javac 1.java会编译通过,但生成的1.class在workspace中,当再编译2.java时,输入javac 2.java会报错找不到1.class,分析这个过程,编译器首先通过类路径指定的目录顺序逐个搜索1.class,按说应当在workspace下找到1.class并进行匹配,而实际情况却是编译器没有找到1.class,这说明1.class由于第一句package chapter的原因使得它的虚拟路径并不属于D:\workspace\,因此编译器是找不到的,而把1.class放入chapter里面则可以编译成功。

————————————————————————————————————————————————————————
转载:
java应用程序文件
这个说法是我自己抽象出来的,指的是一般的组织在package中的所有文件。
大体分成这三种:
1,java程序源文件,扩展名为.java。
2,编译好的java类文件,扩展名为.class。
3,其他文件,除了以上的,就是资源文件。
例如图片文件,xml文件,mp3文件
等等等等都可以组织在package之中。(你当然也可以把一部电影放在package里面,当然
不提倡这样做)

package干吗用?
package就是组织文件的一种方式。
最大的作用就是组织java类文件。
成千上万的class文件,总难免重名吧,即便不重名,那么多你记得住么?当然要分门别类
的组织起来方便你随时取用吧,这个就是package最大的作用。

package是个什么东西?
package本身是一个比较抽象的逻辑概念,它的宗旨是将东西组织在一棵树里面,就好像
linux的文件系统一样,它有一个根,然后从根开始有目录和文件,然后目录中也可以有
目录。而实现的时候是怎样的呢?是利用文件系统的目录结构或者利用压缩文件中的目录
结构来组织的。

package怎么实现的?
首先讲其最重要的应用——组织源代码。
我们知道java源代码的基本单元是一个.java文本文件。
一个.java文件可以包含一个public类和无数包级类,
默认什么访问修饰都没有的类就是一个包级类。这种类只能在本package中使用。
当然了,类当中还可以有类,名唤内隐类,内隐类的访问修饰就可以是protected
或者甚至是private了。
好,那么何谓本package呢?
当你在源代码的最开头(当然,注释可以放在更开头的位置)不写package语句的话,那么
当前编译单元中的所有编译出来的类就只能够放在package的"/"上,这种package我们叫做
defaultpackage。一般我们写个HelloWorld或者简单调几个api实现个小功能的话,一般
采用这种“不打包”似的default package就可以了。
但是,当你的类开始泛滥起来的时候,你就必须考虑给类打个包放在某个package中了。
方法很简单,在所有代码开始之前写一句
package 包名;
即可。
包名是用"."间隔的字符串,一般能够当作文件名的字符串就能用到这里来。
比如
package aaa.bbb.ccc;
意味着这个编译单元所编译出来的class都必须放在/aaa/bbb/ccc这个目录之下。
否则这种类就无法正常使用,正是这种机制保证了类的严格组织。
实际上,当你在编译一些有package语句的编译单元的时候,如果你使用的是命令行的话,
应该使用-d参数让编译器自己生成目录结构,实际上你的.java就应该放在这种目录结构
之中。我举个非常简单的例子,有个人写了这么两个.java文件。
/*   A.java */
package aaa.bbb.ccc;
public class A{
    B b=newB();
}
/* B.java*/
package aaa.bbb.ccc;
public class B{}
然后这个人就把这两个文件就放在当前目录之下,然后javacA.java,
然后傻眼。

说找不到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不得不说的事
讲了半天还是觉得不太清楚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干吗用的?
java几乎所有的api都是用java语言本身写成的,是的,那些你所经常使用的String,
HashSet,HashMap等等这些类都是用java语言写成的。
这些类的制作是我们也可以来做的事情,他们同样是写出一个个java文件,打上不同的
package,然后编译好,最后压缩一下,成为jre里面的dt.jar之类的文件,变成了我们常
常调用的库。
有的人以为,当我们写下importjava.util.*;之前,我们的这些库就是“不可达”的,
而当我们写下了importjava.util.*之后,我们所需要的那个库文件就会被某种不知道的
机制加入到我们的工程。
错!这些人是纯粹打死不看书的想当然类型,只在乎自己的意象,不在乎其所以然。

不管你写还是不写import语句,对当前外部的编译和执行环境都不会有任何的影响。
即便你不写import java.util.*;
你照样可以用java.util.HashMap来调用系统api,根本不用做更多的事情。
这里我不得不再提一次,不要把dt.jar放到CLASSPATH环境变量中,它已经在classpath中
了,而且此举常常让初学者丢掉了默认在classpath中的"."当前目录,让他们一番热情学
java写helloworld的火焰被一盆水扑灭。

import有啥用的呢?
它只不过是一种让你少打点字的方法,就跟c++的名称空间的using语句功能一样,就是暴
露那个package下面所有的类,写代码的时候就可以直接写类名,而不用写下完整的
包名.类名,仅此而已。
不得不提的是,*仅仅代表类名,不负责以下更深层次中各级目录中的东西。
importjava.*;实际上没有暴露任何类,因为没有类是打在这个包里面的。它没有
暴露java.util.*,也没有暴露java.sql.*等等,它仅仅暴露了java目录下面所有的类。

打包成jar文件
一般的打包成jar文件,除了将目录结构压缩存储在一个zip格式但是扩展名比较畸形的
文件中之外没有做任何事情。
jar文件可以用任何能够解压zip的工具来解压,如果你讨厌使用jar命令行,你甚至可以
直接使用winrar来压缩,然后改个名字即可。
当然了,jar文件也有别的用处,比如“可直接执行的jar”。
“可直接执行的jar”跟“不可直接执行的jar”的区别仅仅在于它多了一个配置文件在
jar文件中,这个文件中指出了一个完整的类名,告诉java.exe或者javaw.exe,main方法
这个类里面而已。
欲知道更多关于jar文件的用法,请参考精华区。

从实践到理论

刚才我用一个非常简单但是非常完整的例子给大家演示了java的package机制。
为什么以前脑海里面那么简单的javac会搞得这么复杂呢?

实际上它本就这么复杂,
并不是一个.java,一行javac一个当前目录中的class这么简单。

首先我要打破一些东西,然后才好建立一些东西。
javac并非只是给一个.java编译一个class的。javac自带有make机制,也就是说,如果在
javac的参数中java文件使用到的任何类,javac首先会去找寻这个类的class文件存在与否
,如果不存在,就会在sourcepath中找寻源代码文件来编译。

什么是sourcepath呢?sourcepath是javac的一个参数,如果你不加指定,那么sourcepath
就是classpath。

比如我们装好jdk之后,我说过不要设定classpath环境变量,因为大部分人一旦设定了
classpath,不是多此一举把什么dt.jar放进去。(我可以好好打击你一下,告诉你一个可
悲的事实——jre永远不会从你这个classpath中去寻找dt.jar。你完全是徒劳的!)就是
把"."搞不见了,搞得是冷水一盆盆的往自己身上泼,脑袋一点点的涨大。

不要设!classpath没有你想象中那么普适和强大,它只是命令行的简化替代品。
你不设的话它就是"."。


回到sourcepath,sourcepath指的是你源代码树的存放地点。
为什么是源代码树?而不是一个目录的平板源代码呢?
请大家将原本脑海中C的编译过程完全砸掉!
java完全不同,java没有头文件,每个.java都是要放在源代码树中的。
那么这颗树是怎么组织的呢?
对了,就是package语句。
比如写了package com.lightning;
那么这个.java就必须放在源代码树根\的com\lighting\之下才行。

很多浮躁的初学者被default打包方式宠坏了。自我为中心,以为java就是一套库,自己写
的时候最多import进来就行了,代码从不打包,直接javac,直接java,多么方便。
孰不知自己写的这个.java也不过是java大平台的其中一个小单元而已。如果不打包,
我写一个Point,你写一个Point,甚至更有甚者敢于给自己的类起名叫String等等。
全部都在平板式的目录中,那jre该选哪一个?

一旦要使用package语句,就要使用代码树结构,当然,你要直接javac,也行。
不过javac出来的这个class要放在符合package结构的目录中才能发挥正常作用,否则就是
废物一坨。
而且,如果你这个.java还用到其它自己写的有package语句的.java,那这个方法就回天乏
术了。

按照sun的想象,应该是写好的.java放在符合package结构的目录中,package语句保证了
正确放置,如果目录位置和package语句中指示的不同,则会出错。

所以按照刚才我们的那种package写法,我们必然要将那几个.java文件放入相应的目录中
才能让javac顺利找到他们来make。

有人说javac可不可以像java那样 java aaa.bbb.c...java?
不可以
javac中的那个.java文件参数必须是一个文件系统的路径文件名形式。
然后如果用到其它的.java,javac会根据目前的sourcepath出发寻找目录结构中的那些
java文件。

当然了,既然打了包,在使用的时候。
要么写全名——包名.类名
或者使用import
不得不提的是,import就好比c++的using,它不负责做文件操作,它只是方便你写代码。

另外import语句中的*代表的是类名,不代表包名片断。
你import com.*;
编译器仍然找不到com.lightning中的任何类。
反之亦然。
就好象你告诉编译器,我这里面要用到姓诸葛的人。
那么姓诸的人当然编译器不会认为也包含在内。


所以,如果程序一旦写到一定规模。
就不得不使用ant来管理这些。
或者使用IDE,否则jdk就真的变成了java developer killer。

但是对于初学者,在了解为什么会有ant之类的之前,还是要体会一下使用
jdk的艰辛。

这个和以前在unix上开发的人用gcc命令行到后来使用make之后使用ide
之类的时候的体会是类似的。

最后,javac的-d参数是指示编译出来的class文件放在哪里的,如果你不指定的话,它们
和.java混在一起。当然也符合目录结构

0 0
原创粉丝点击