包(package)是类和接口的集合,利用包可以把常用的类或功能相似的类放在一个包中。Java还提供了系统包。
接口(interface)解决了Java不支持多重继承的问题,可以通过实现多个接口达到与多重继承相同的功能。
6.1 包
包是Java提供的一种区别类名空间的机制,是类的逻辑组织形式,一个包对应一个文件夹,包中还可以有包,称为包等级。
当源程序中没有声明类所在的包时,Java将类放在默认包中,即运行编译器的当前文件夹中。这时不能出现重复的类名。
6.1.1 Java的系统包
Java提供了大量的类,为便于管理和使用,分为不同的包。这些包又称类库或API包,所谓API(application program interface)即应用程序接口。API包一方面提供丰富的类与方法供大家使用,如画图形、播放声音等,另一方面又负责和系统软硬件打交道,把用户程序的功能圆满实现。
许多Java API包都以“java.”开头,以区别用户创建的包。
1.java.lang
是Java语言的基础类库,包含基本数据类型、数学函数、字符串等。这是唯一自动引入每个Java程序的类库。Java.lang包中包含有以下主要类:
(1)Object 类:是Java类层次的根,所有其他类都是由Object类派生出来的。其定义的方法,在其他类中都能使用。如:复制方法clone( ),获得对象的类getClass( )方法,两个对象是否相等的equals( )方法,将对象输出为字符串的toString( )方法等
在比较两个变量、两个值、对象与变量相等时使用“==”,在比较两个对象相等时使用equals()
char ch='a' ;if(ch=='a'||ch=='A');
String S1="123" ,S2="123" ;
if(S1==S2)
System.out.println(S1.equals(S2)); // 与S1= =S2效果一样,true
System.out.println(ch.equals(S2)); //错
(2)数据类型包装类:
(3)数学Math类:如常数E和PI,数学方法sin和cos等,Math是最终类,其中的数据和方法都是静态的(直接用类名引用)
(4)字符串String和StringBuffer类
(5)系统System类:提供访问系统资源和标准输入输出方法
如:System.out.print (<输出量>)
System.exit(0) // 结束当前程序的运行
System类的变量和方法都是final和static
(6)运行时Runtime类:可以直接访问运行时的资源
如:totalMemory方法可返回系统内存总量
freeMemory方法返回内存剩余空间
(7)线程Thread类
(8)类操作class和classLoader类:
如: this.getClass( ).getName( ) // 返回当前对象的类名
(9)错误和异常处理类:Throwable , Exception , Error
2.java.util包
提供了实现各种低级实用功能的类,如日期类、集合类等
(1)Date类:构造方法Date()可获得系统当前日期和时间
(2)Calender类:将Date对象的数据转换成YEAR , MONTH , DATE , DATE_OF_WEEK等常量,Calender类没有构造方法,可用getInstance方法创建一个实例,再调用get方法和常量获得日期或时间的部分值。
如:Calender now=Calender.getInstance( ); // 创建类Calendar的实例,并获得系统日期和时间
int year=now.get(Calender.YEAR) ; // 用get方法得到当前年份
GregorianCalendar类是Calender类的子类,实现标准的Gregorian日历
(3)随机数Random类
3.java.io包
是Java语言的输入输出类库,Java语言的文件操作都是由该类库中的输入输出类(FileInputStream和FileOutputStream)实现的,java.io包除了包含标准输入、输出类外,还有缓存流、过滤流、管道流和字符串类等
4.java.net包
支持TCP/IP网络协议,并包含Socket类及URL和URL相联系的类
5.java.awt包
提供了创建图形用户界面的全部工具。如:窗口、对话框、按钮、复选框、列表、菜单、滚动条和文本区等类;用于管理组件排列的布局管理器类Layout;以及常用颜色类Color、字体类Font。Java.awt.event类库用来处理各种不同类型的事件。
6.java.applet包
是所有小应用程序的基础类库。它只包含了一个Applet类和三个接口AppletContext , AppletStub , AudioClip,所有小应用程序都是从该类中派生的。
7.java.security包
包括java.security.acl和java.security.interfaces子类库,利用这些类可对Java程序进行加密,设定相应的安全权限等。
6.1.2 包的引用
1.导入包语句
格式:import <包名1>[.<包名2>……] .<类名>|* ;
说明:如果有多个包或类,用“.”分割,“*”表示包中所有的类。
例: import java.applet.Applet // 导入java.applet包中的Applet类
import java.awt.* // 导入java.awt包中的所有类
java.lang包是系统自动隐含导入
2.包的路径
由于Java使用文件系统来存储包和类,类名就是文件名,包名就是文件夹名,设置环境变量用classpath方法
6.1.2 声明自定义包
1.创建自定义包
格式: package <包名>
说明:(1)声明包语句必须添加在源程序的第一行,表示该文件的全部类都属于这个包
(2)可以在不同的文件中使用相同的声明语句,可将不同文件中的类都包含在相同的包中
(3)若在程序中没有声明包,类就放在默认的包中,这个包没有名字,默认包适用于小的程序。
例:见P108 YMD.java文件内容:
package Mypackage; // 声明一个Mypackage包,区分大小写
import java.util.*;
public class YMD{
private int year,month,day;
public static void main(String []args) {}
public YMD(int y, int m ,int d){
year=y;
month=(((m>=1)&(m<=12))?m:1);
day=(((d>=1) & (d<=31))?d:1); }
public YMD(){
this(0,0,0); }
public static int thisyear(){
return Calendar.getInstance().get(Calendar.YEAR); }//获得当年的年份
public int year(){
return year; }
public String toString(){
return year+"-"+month+"-"+day; //转化为字符串
}}
说明:建立Mypackage(区分大小写)文件夹,并将YMD.class复制该文件夹下
*******************************************
P3.java文件内容:
import Mypackage.YMD;
public class P3{
private String name;
private YMD birth;
public static void main(String args[]){
P3 a=new P3("张弛",1990,1,11);
a.output();}
public P3(String n1,YMD d1){
name=n1;
birth=d1; }
public P3(String n1,int y,int m,int d){
this(n1,new YMD(y,m,d)); //初始化变量与对象,调用上一个构造方法}
public int age()
{return YMD.thisyear()-birth.year(); //计算年龄 }
public void output(){
System.out.println("姓名: "+name);
System.out.println("出生年龄: "+birth.toString());
System.out.println("今年年龄: "+age());
}}
2.设置包的路径
用自定义包名建立一个文件夹,如:c:\ Mypackage
设置路径:set classpath=. ; c:\j2sdk1.4.2 ; c:\mypackage
以后其它类使用自定义包里的类用命令:import Mypackage.*
3.创建包等级
格式: package <包名1>[.<包名2>][.<包名3>][.<……>]
4.包的访问权限
同一个类中
同一个包中
不同包中的子类
不同包中的非子类
private
√
protected
√
√
√
public
√
√
√
√
friendly
√
√
5.编译和运行包(补充)
例:package p1;
public class SC{
public static void main(String args[]){
System.out.println("演习!"); }}
操作要求::
(1)编译文件方法一:javac SC.java
(2)新建p1文件夹,将SC.class存入其中;
(3)在p1文件夹的上一级文件夹中运行 java p1.SC
说明:因为SC.class存在p1包中,对它的引用应是: p1.SC.class,所以在p1目录下运行java SC则错,java p1.SC也错,必须退到上一级,运行java p1.SC才正确。
编译文件方法二:javac –d . SC.java
系统行动在当前文件夹(.)下新建p1文件夹,且将SC.class自制到p1文件夹下
6.2 接口
与C++语言不同,Java语言不支持多重继承,为了实现多重继承的功能,Java提供接口来实现,且比多重继承具有更强的功能。
多重继承指一个类可以是多个类的子类
接口可以看作是没有实现的方法和常量的集合。接口与抽象类相似,接口中的方法只是做了声明,而没有定义任何具体的操作方法。
接口功能:
(1)通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系
(2)通过接口可以指明多个类需要实现的方法
(3)通过接口可以了解对象的交互界面,而不需了解对象所对应的类。
6.2.1 实现系统提供的接口
接口中定义的变量全部隐含为了final和static,表明这些变量不能被实现接口方法的类改变,这些变量还必须设置初值。如果接口为public,则接口中的方法和变量也全部为public,否则只能被处于同一包中的成员访问。
类引用接口不叫继承而称为实现。
系统接口,如MouseListener和MouseMotionListener接口,定义了处理鼠标事件的方法。
格式: class <类名> implements <接口名>[,<接口名>]
例:P110
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class SC extends Applet implements MouseListener , MouseMotionListener{
int x1,y1,x2,y2;
public void init( )
{ addMouseListener(this);
addMouseMotionListener(this); }
public void paint(Graphics g){
g.drawLine(x1,y1,x2,y2); // 书上在这错
}
public void mousePressed(MouseEvent e){ //习惯写成e,换成别的字符也行
x1=e.getX();
y1=e.getY(); }
public void mouseClicked(MouseEvent e){ }
public void mouseEntered(MouseEvent e){ }
public void mouseExited(MouseEvent e){ }
public void mouseReleased(MouseEvent e){ }
public void mouseDragged(MouseEvent e){
x2=e.getX();
y2=e.getY();
repaint(); }
public void mouseMoved(MouseEvent e){ }
}
说明:在实现接口时,要实现所有接口中定义的所有方法,方法的实现要以具有具体的实现内容,也可以是空的方法,即只有方法名或参数,没有变量、没有具体操作语句
6.2.2 创建自定义接口
格式:[修饰符] <interface> <接口名>
{ 静态常量及方法声明 }
说明:(1)Java系统会自动把接口中声明的变量当作static final类型,不管是否使用了这些修饰符,且必须赋初值,这些变量值都不能被修改。
(2)接口中的方法默认为abstract,不管有没有这些修饰符。
(3)接口若是public,那么该接口可被任意类实现,否则只有与接口在同一个包中类的实现。
(4)接口若为public,则接口中的变量也是public。
例:interface Colle{
int Max_Num=100;
void add(Object obj);
void delete(Object obj);
Object find(Object obj);
int currentCount( ); }
}
例:见P112
6.2.3 接口的继承关系(自学)
1.接口的单继承
接口之间的继承与类的继承一样使用extends
格式: interface <新接口名> extends <已有接口名>
例:见P113
如果一个类实现了接口B,那么它必须实现接口A和接口B中的全部方法。
2.接口的多重继承
在Java语言中,不支持类的多重继承,但支持接口的多重继承
格式: interface <新接口名> extends <已有接口名1>[<,接口名2>…]
注意:引用接口时,必须实现接口中的所有方法。
6.3 异常处理
错误分编译错误和运行错误。编译错误主要是程序中的语法错误,可以在程序编译过程中发现。而而运行错误就复杂得多,有些只在程序运行过程中才会暴露出来。
Java语言的错误处理机制—异常处理,可以监视某段代码是否有错,并且将各种错误集中处理。
以往需要由程序员完成的程序出错情况判别,在Java中改为由系统承担
6.3.1 什么是错误与异常
运行错误分致命错误和异常两种类型
1.致命性错误
如死循环或内存溢出,运行时程序本身无法解决,只能依靠其他程序干预,否则会一直处于不正常状态。
2.异常
如除数为0,操作数超出数据范围,打开文件不存在等
6.3.2 异常发生的原因
(1)Java虚拟机检测到了非正常的执行状态,这些状态可能是由以下几种情况引起的:
* 表达式的计算违反了Java语言的语义,例如整数除数为0
* 在载入或链接Java程序时出错
* 超出了某些资源限制,例如使用了太多的内存
这些异常都是无法预知的。
(2)Java程序代码中的throw语句被执行
(3)异步异常发生:
* Thread的stop方法被调用
* Java虚拟机内部错误发生
6.3.3 异常处理机制
1.抛出异常
当发生异常时将会抛出(throw)异常,即产生一个异常事件,生成一个异常对象,并把它提交给运行系统,再由系统找相应的代码来处理异常。一个异常对象可以由Java虚拟机产生,也可以由运行的方法生成。异常对象中包含了异常事件类型、程序运行状态等必要信息。
2.捕获异常
异常抛出后,运行时系统从生成异常对象的代码开始,没方法的调用栈进行查找,直到找到包含相应处理的方法代码,并把异常对象交给该方法为止,这个过程称为捕获(catch)异常。
简单说异常处理机制:当语义限制被违反时,将会抛出异常对象,并将引导程序流程从异常发生点转移到程序员指定的处理异常方法代码处进行异常处理。
6.3.4 异常对象类型(补)
异常类都是Throwable的子类,一般说程序不捕获也不抛出类Error的对象(包括动态链接失败、虚拟机错误等),而只处理Exception类的各子类对象
java.lang.Object-->java.lang.Throwable-->java.lang.Error
-->java.lang.Exception
-->java.lang.RuntimeException
-->java.lang.IOException
参见P116
6.3.5 异常的处理
格式: try {……} // 被监视的代码段
catch(异常类型1 e) // 要处理的第一种异常
catch(异常类型2 e) // 可以不写成e
…………
finally {……} //最终处理
对异常进行处理时,一般是把可能会发生异常情况的代码放在try语句段中,利用try语句对这组代码进行监视。发果发生了第一种异常,使用第一个catch中的代码段处理;如果发生了第二种异常,则使用第二个catch代码段处理。
如果希望在异常发生时能确保有一段代码被执行,那么应该使用finally子句。
catch语句在执行前,必须识别抛出的异常对象类型是catch能够捕获的“异常类”如果catch语句参数中声明的异常类与抛出的异常类相同,或者是它的父类,catch语句就可以捕获任何这种异常类的对象。e为相应的异常对象。
例6.5 :见P115
如果不能确定会发生哪种情况的异常,那么最好指定catch的参数为Exception,即说明异常的类型为Exception。
例6.6 :见P116
捕获例外的顺序是和不同catch语句的顺序相关的,因此在安排catch语句顺序时,首先应该捕获最特殊的例外,然后再逐渐一般化,如果一个异常类和其子类都出现在catch子句中,应把子类放在前面,否则将永远不会到达子类。另如果catch语句所捕获的例外类型不是一个“终极”类型(即它还有子类),则一个catch语句可以同时捕获多种例外。
例:P117
例:public class SC{
int count =1;
public static void main(String args[])
{SC abc=new SC();}
public SC( ){
while(true){
try{ int x=6/(count--);
System.out.println("in try,no exception") ; }
catch(ArithmeticException e)
{ System.out.println("in catch,divided by zero");}
finally{
System.out.println("in finally");
if (count==-1) break; }
} System.out.println("end of program"); } }
运行结果:in try,no exception
in finally
in catch,divided by zero
in finally
end of program
6.3.6 throw语句
异常对象可以是Java系统抛出的。也可以通过代码实现,使用throw语句就可以明确抛出一个异常。
格式:throw <异常对象>
如:IOException e new IOException( ) ;
throw e;
例:P118
6.3.7 throws子句
throws用来表明一个方法可能抛出的各种异常,并说明该方法会抛出但不捕获异常。
1.抛出异常的方法(自学)
2.调用方法处理异常(自学)
3.由方法抛出异常交系统处理
对于程序中需要处理的异常,一般编写try-catch-finally语句捕获处理,而对于程序中无法处理必须由系统处理的异常,可以使用throws语句在方法中抛出异常交由系统处理。
格式:返回类型 方法名(参数表) throws 异常类型表
例:P123
例:public int read( ) throws IOException{……}
说明:(1)该方法将不对这些例外进行处理,而是声明抛弃它们。
(2)对于非运行时例外,如前IOException等,程序中必须要作出处理,或者捕获,或声明抛弃。而对于运行时例外,如ArithmeticException, IndexOutOfBoundsException,则可以不做处理。
6.3.8 finally语句
每个try语句至少要有一个与之相匹配的catch或finally子句。
例:P121
finally子句总是在方法返回前执行
6.3.9 编译时对异常情况的检查
1.可检测的异常
在编译时,编译器将分析哪些方法会产生可检测的异常,然后检查方法中的可检测异常的处理部分。如果方法中没有异常处理部分,就要在方法的throws子句说明该方法会抛出但不捕获的异常,以告知调用它的其他方法,即将异常上交给调用者处理。
如果程序在运行的过程中抛出异常,而这个异常是可检测的,则在程序中必须捕获这个异常进行处理或声明抛弃(throws)该异常,捕获异常可以使用try语句,而抛弃异常在方法声明时声明,即在方法声明后加上throws xxxException子句,抛弃外个异常时可在各异常间使用“,”分隔。
例P123:
import java.io.*;
public class SC{
public static void main(String a[]) throws IOException {
//省略throws IOException 编译时即报错
FileInputStream fis=new FileInputStream("a2.txt"); }}
2.不可检测的异常(运行时异常类)
不可检测的异常类是RuntimeException及其子类、Error及其子类,其他异常类则是可检测的类。编译器对不可检测的异常类不进行检查。
解释器在执行程序时会对出现异常的程序给出异常报告。
6.3.10 创建自己的异常类(自学)
格式:<class> <自定义异常名> <extends> < Exception>{……}
在使用各种例外类型时,建议:
(1)对于运行时例外,如果不能预测它何时发生,程序可以不做处理,而是让虚拟机处理它。
(2)如果程序可以预知运行时例外可以发生的地点和时间,则应该在程序中进行处理,而不应简单地把它交给运行时系统。
(3)在自定义例外类时,如果它所对应的异常事件通常总是在运行时产生的,而且不容易预测它将在何时、何处发生,则可以把它定义为运行时例外,否则应定义为非运行时例外。
使用异常处理准则:
(1)尽可能在当前程序中解决问题,否则应将异常向更外层的程序抛出。
(2)简化编码,不要因加入异常处理而使程序变得复杂难懂。