文章目录
面向对象考试复习指南
1、语言基础
(1) Java语言的历史和Java程序的执行机制
1)Java成员
Java SE: Java最通用的版本,用于Pc的标准平台,适合初学使用
Java EE:工业中应用最广泛
Java ME:应用于嵌入式平台开发,现在很少用
2)Java历史
1996年1月:JDK 1.0第一次发布
如今(2021/9/20)已经更新到了16
3)JDK、JRE、JVM、API
JDK(Java Development Kit):Java开发工具包
JRE(Java Runtime Enviroment):是Java的运行环境
JVM( java virtual machine) :即Java虚拟机。引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
API:是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。类似于Java的字典。
JDK是面向开发者的,JRE是面向使用JAVA程序的用户
4)Java程序执行机制
运行一个Java程序的步骤:
1、编辑源代码xxx.java
2、编译xxx.java文件生成字节码文件xxx.class
3、JVM中的类加载器加载字节码文件
4、JVM中的执行引擎找到入口方法main(),执行其中的方法
(2) 标识符与保留字
1)标识符
标识符的长度不限,但第一个字符必须是这些字符之一:大写字母(A-Z). 小写字母(a-z)、下划线、$符号,标识符的第二个字符及后继字符可以包括数字字符(0~ 9)。
2)保留字
abstract |
continue |
for |
new |
switch |
---|---|---|---|---|
assert | default | goto | package | synchronized |
boolean | do |
if | private | this |
break | double | implements | protected | throw |
byte | else | import | public | throws |
case | enum | instanceof | return | transient |
catch | extends | int | short | try |
char | final | interface | static | void |
class | finally | long | strictfp | volatile |
const | float | native | super | while |
(3) 初始化
1)变量的初始化
变量定义包括变量名、变量类型和变量值几个部分,定义变量的基本格式为:
数据类型 变量名 = 值
int n = 5;
Java中变量的默认初始值都是确定的
布尔类型:false 整数变量:0 浮点数:0.0 引用(类)变量:null
2)数组的初始化
Java数组在创建时会为每个元素赋予默认初始值也可以不采用默认值方式,而是对数组元素进行初始化,例如:
int a[]={22, 33,44,55};
int[] anArray = { 100, 200, 300,400, 500, 600, 700, 800};
String wkdays[] = {"mon" , "Tue", "Wed", "Thu", "Fri"};
或者等到数组创建完毕后,再分别为数组元素赋予适当的值之后再使用。例如,为int类型数组元素赋值方式如下:
int orange[ ] = new int[100]; // 创建100个int型元素,默认初始值为0
orange[7] = 32; // 为其中一个元素赋值32
基本数据类型数组的初始化比较简单,如果数组的元素是引用类型,这样的数组称为**“对象数组”,对象数组的初始化相对复杂-一 些,不仅需要为数组分配空间,而且要为数组中的每个元素分配空间**,使用前还需要给所有元素一一赋值(即new一个对象)。
(4) 基本数据类型的范围与常量表达方式
1)布尔型
-
布尔型只有true和false
-
Java中的boolean和int完全不同,true不等于1,false不等于0
-
定义为:
boolean b = true
-
可参与逻辑运算
&& || == != !
2)字符类型
表示单个字符,占有两个字节,注意加单引号 ’ ’
字符变量
Java中涉及char、byte、short的运算操作,都会先将这些值转换为int,然后再对int类型进行计算,所以int和char’的运算结果为int
char c ='1'
System.out.println(c+0) //结果为49
char d = '\u0031'
System.out.println(d) //结果为1
3)整型
-
Java各整数类型有固定的表数范围和字段长度,不受具体OS的影响,以保证java程序的可移植性。
-
Java的整型常量默认为 int 型,声明long型常量须后加‘l’或‘L’
-
java程序中变量通常声明为int型,除非不足以表示较大的数,才使用long
类 型 | 占用存储空间 | 表数范围 |
---|---|---|
byte | 1字节=8bit位 | -128 ~ 127 |
short | 2字节 | -2^15 ~2^15-1 |
int | 4字节 | -2^31 ~ 2^31-1 (约21亿) |
long | 8字节 | -2^63 ~ 2^63-1 |
4)浮点数类型
-
Java 浮点类型也有固定的表数范围和字段长度,不受具体操作
-
浮点型常量有两种表示形式:
- 十进制数形式:如:5.12 512.0f .512 (必须有小数点)
- 科学计数法形式:如:5.12e2 512E2 100E-2
-
float:单精度,尾数可以精确到7位有效数字。很多情况下,精度很难满足需求。double:双精度,精度是float的两倍。通常采用此类型。
-
Java 的浮点型常量默认为double型,声明float型常量,须后加‘f’或‘F’。
类 型 | 占用存储空间 | 表数范围 |
---|---|---|
单精度float | 4字节 | -3.403E38 ~ 3.403E38 |
双精度double | 8字节 | -1.798E308 ~ 1.798E308 |
5)数据类型转换与字符串整型转换
- 数据类型可以自动类型转换,int、long、float数据可以混合运算,混合运算是,转换由低级向高级
- boolean类型不能与其它数据类型运算
(5) String与StringBuffer类的使用
1)字符串类String
Java提供了两种处理字符串的类String和StringBuffer。Java将String类作为字符串的标准格式,Java 编译器把字符串转换成String对象。
1️⃣ 字符串声明及初始化
Java中的字符串分为常量和变量两种,常量初始化可由直接给一个String对象赋值完成,字符串变量在使用前同样要声明和初始化,初始化过程一般有 下面几种形式。
1) 直接用字符串常量来初始化字符串:
String s3 = "Hello! ";
2) 由字符数组创建字符串:
char ch[ ] = {'s', 't, 'o, 'r, 'y'};
3) 创建一个String类对象并赋值:
String s2 = new String ("Hel1o");
4) 字符串数组形式:
String[] strArray;
strArray = new Str
sttarray,onew sString[8]
strArray[1]= "World";
2️⃣ 字符串连接
String类的concat()方法可将两个字符串连接在一起
string1.concat (string2) ;
string1调用concat()将返回一个stringl和string2连接后的新字符串。字符串连接通常还有另一种更为简洁的方式,通过运算符+连接字符串:“abc”+“def" =“abcdef" ;
“+”不仅可以连接多个字符串,而且可以连接字符串和其他的基本数据类型,只要+ 两端其中-个是字符串,另一个非字符串的数据也会被转换为字符串,然后进行字符串连接运算。
示例:测试String类的常用方法,实现字符串替换、单个字符检索、查找子串、比较、去空格等功能
public class Ex3_StringMethodTest {
//测试String类的常用方法,实现字符串替换、单个字符检索、查找子串、比较、去空格等功能
public static void main(String[] args) {
String str = "Welcome to Java";
System.out.println(str+"的字符长度为: "+str.length());
System.out.println(str+"中第五个字符是:"+str.charAt(5));
System.out.println(str+"与hello world相同:"+ str.equalsIgnoreCase("hello world"));
System.out.println(str+"用'L'代替'l'以后为:"+str.replace("l","L"));
System.out.println(str+"用'J'结尾:"+str.endsWith("J"));
System.out.println(str+"从第五个字符开始的字串为:"+str.substring(5));
System.out.println(" Thanks "+"去掉开头和结尾的空格为:"+" Thanks ".trim());
}
}
运行结果如下:
Welcome to Java的字符长度为: 15
Welcome to Java中第五个字符是:m
Welcome to Java与hello world相同:false
Welcome to Java用'L'代替'l'以后为:WeLcome to Java
Welcome to Java用'J'结尾:false
Welcome to Java从第五个字符开始的字串为:me to Java
Thanks 去掉开头和结尾的空格为:Thanks
2)字符串类StringBuffer
StringBuffer类也是用来处理字符串的,它提供的功能很多与String类相同,但比String 更丰富些。两者的内部实现方式不同,String 类对象创建后再更改就产生新对象,而StringBuffer 类的对象在创建后,可以改动其中的字符,这是因为改变字符串值时,只是在原有对象存储的内存地址上进一步操作,不生成新对象,内存使用上比String有优势,比较节省资源。所以在实际开发中,如果经常更改字符串的内容,比如执行插入、删除等操作,使用StringBuffer更合适些,但StringBuffer不支持单个字符检索或子串检索。
示例:测试StringBuffer类,实现字符串的内容替换、反转等功能
public class Ex3_StringBufferTest {
//测试StringBuffer类,实现字符串的内容替换、反转等功能
public static void main(String[] args) {
String str1 = "Welcome to Java";
StringBuffer sf1 = new StringBuffer();
sf1.append(str1);
System.out.println("字符串sf1为:"+sf1);
System.out.println("字符串sf1的长度为:"+sf1.length());
System.out.println("字符串sf1的容量为: "+sf1.capacity());
sf1.setCharAt(2,'E');//更改字符串中的字母
System.out.println("修改以后的字符串为:"+sf1);
sf1.reverse();
System.out.println("倒转以后的字符串为:"+sf1);
sf1.replace(0,5,"hello");
System.out.println("用hello替代以后的字符串为:"+sf1);
}
}
运行结果如下:
字符串sf1为:Welcome to Java
字符串sf1的长度为:15
字符串sf1的容量为: 16
修改以后的字符串为:WeEcome to Java
倒转以后的字符串为:avaJ ot emocEeW
用hello替代以后的字符串为:helloot emocEeW
3)字符串与其他数据类型的转换
如何将字串 String 转换成整数 int?
有2个方法:
1). int i = Integer.parseInt([String]); 或
i = Integer.parseInt([String],[int radix]);
2). int i = Integer.valueOf(my_str).intValue();
//注: 字串转成 Double, Float, Long 的方法大同小异.
如何将整数 int 转换成字串 String ?
有3种方法:
1.) String s = String.valueOf(i);
2.) String s = Integer.toString(i);
3.) String s = "" + i;
//注: Double, Float, Long 转成字串的方法大同小异.
字符串转化为字符数组
String str="123456";
char[] c = str.toCharArray() ;
2、运算符和赋值
(1) 运算符
1)算术运算符
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | b=4; -b | -4 |
+ | 加 | 5+5 | 10 |
- | 减 | 6-4 | 2 |
***** | 乘 | 3*4 | 12 |
/ | 除 | 5/5 | 1 |
% | 取模(取余) | 7%5 | 2 |
++ ++ |
自增(前):先运算后取值 自增(后):先取值后运算 |
a=2;b=++a; a=2;b=a++; |
a=3;b=3 a=3;b=2 |
- - - - |
自减(前):先运算后取值 自减(后):先取值后运算 | a=2;b=- -a a=2;b=a- - |
a=1;b=1 a=1;b=2 |
+ | 字符串连接 | “He”+”llo” | “Hello” |
2)关系运算符
运算符 | 运算 范例 结果 |
---|---|
== | 相等于 4==3 false |
!= | 不等于 4!=3 true |
< | 小于 4<3 false |
> | 大于 4>3 true |
<= | 小于等于 4<=3 false |
>= | 大于等于 4>=3 true |
instanceof | 检查是否是类的对象 “Hello” instanceof String true |
- 比较运算符的结果都是boolean型,也就是要么是true,要么是false。
- 比较运算符“==”不能误写成“=”
3)逻辑运算符
&—逻辑与 | | —逻辑或 | !—逻辑非 |
---|---|---|
&& —短路与 | || —短路或 | ^ —逻辑异或 |
a | b | a&b | a&&b | a|b | a||b | !a | a^b |
---|---|---|---|---|---|---|---|
true | true | true | true | true | true | false | false |
true | false | false | false | true | true | false | true |
false | true | false | false | true | true | true | true |
false | false | false | false | false | false | true | false |
- 逻辑运算符用于连接布尔型表达式,在Java中不可以写成3<x<6,应该写成x>3 & x<6 。
- “&”和“&&”的区别:
- 单&时,左边无论真假,右边都进行运算;
- 双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
- “|”和“||”的区别同理,||表示:当左边为真,右边不参与运算。
- 常用!、&&、||
4)位运算符
位运算符 | ||
---|---|---|
运算符 | 运算 | 范例 |
<< | 左移 | 3 << 2 = 12 --> 322=12 |
>> | 右移 | 3 >> 1 = 1 --> 3/2=1 |
>>> | 无符号右移 | 3 >>> 1 = 1 --> 3/2=1 |
& | 与运算 | 6 & 3 = 2 |
| | 或运算 | 6 | 3 = 7 |
^ | 异或运算 | 6 ^ 3 = 5 |
~ | 取反运算 | ~6 = -7 |
位运算是直接对整数的二进制进行的运算
5)其他运算符
条件赋值:
op1?op2:op3
(y<5)?y+6:y//当y<5时,计算结果为y+6;否则计算结果为y
(2) 方法参数传递
方法中不可避免使用到参数,接下来具体分析Java方法中的参数是如何传递的。Java参数可以是基本数据类型,也可以是引用(类)类型。在Java语言中,基本数据类型作为参数时,均采用传值( passing-by-value)的方式完成,对形参的任何改动都不会影响到实参。而引用类型变量作为参数传递时,采用的是引用传递( passing-by-reference)的方式,在方法体中对形参的改动将会影响到实参。
简单解释一下实参和形参的概念,实参是在调用时传递给方法的实际参数;形参是在定义方法名和方法体时使用的参数,目的是接收调用该方法时传人的参数。实参可以是常量.变量、表达式、方法等,无论实参采用何种类型,在调用方法时,它们都必领具有确定的
值,以便把这些值传送给形参,因此应预先用赋值、输人等办法使实参获得确定值。
当以基本数据类型为参数时,采用传值方式实现,形参仅是实参的一个拷贝, 它们的值相同,但是各自占有独立的内存地址空间,任何对形参的更改都不会影响到实参。而当以引用类型数据为参数时,采用引用传递方式实现,形参即为实参的别名,形参指向实参的内存地址空间,使用时便如同使用实参一样,任何对形参的更改都是对实参的更改。在实际开发中,常常会遇到需要改变对象数据的问题,这时应该考虑使用引用传递的方式来完成。
然而String类型虽然属于引用类型,但作为参数时采用的是传值方式来完成。String 类型对象一旦创建后就不可更改,重新赋予新值实际上是另外开辟内存地址进行存储,相当于创建了两个对象。所以方法中传递的参数类型为String时,形参和实参是两个对象,它们值相同,但各占一份独立的内存地址空间,对形参的任何更改都不会影响到实参,实际为传值效果,使用时需要注意。
3、流控制和异常处理
(1) 流控制
Java中的流程控制结构大体上分为三种:分支结构(if-then、if-then-else、switch)、循环语句(for、while、do-while)以及中断语句(break、continue、return)
1)分支结构
1、if 语句
语法如下:
if(op1)
exec1;
else if(op2)
exec2;
...
else execn;
2、switch语句
switch语句是一个多分支的选择语句,可以对多种情况进行判断并决定是否执行语句,其结构如下:
switch(表达式)
{
case 值1:语句1;break;
case 值2:语句2;break;
case 值3:语句3;break;
default: 语句4
}
switch语句使用时,首先判断表达式的值,如果表达式的值和某个case后面的值相同,则从该case之后开始执行,若满足值1,则执行语句1,满足值2,则执行语句2,直到break语句为止。default可有可无,若没有一个常量与表达式的值相同,则从default之后开始执行。
2)循环语句
1、for循环语句
for循环结构是Java三个循环语句中功能较强、使用较广泛的一个,结构上可以嵌套。for循环需要在执行循环体之前测试循环条件,其一般语法格式如下:
-
for(初值表达式; boolean测试表达式 ; 改变量表达式){ 语句或者语句块 }
2、while循环语句
执行while语句,当他的控制表达式为真时,while语句重复执行一个语句或者语句块,通用格式如下
while(条件表达式){
语句或者语句块
}
举例:使用while循环接受并输出从键盘读入的字符,直到输入的字符为回车符
char ch = 'a';
while(ch != '\n'){
System.out.println(ch);
ch=(char)System.in.read();//接收键盘输入
}
3、do-while循环语句
do-whie的一般语法结构如下:
do{
语句或语句块
}while(条件表达式)
do-while的使用与while语句很类似,不同的是**它首先无条件地执行一遍循环体,**再计算并判断循环条件,若结果为true,则重复执行循环体,反复执行这个过程,直到条件表达式的值为false为止;反之,若结果为false跳出循环,则执行后面的语句。
3)中断结构
1、break语句
break语句不单独使用,常运用于swtich、while、do-while 语句中,使程序从当前执行中跳出,不执行剩余部分,转移到其他部分。
break语句在for循环及while循环结构中,用于终止break语句所在的最内层循环。示例代码片段如下:
int i = 0;
while(i<10){
i++;
if(i==5){
break;
}
}
该循环在变量i的值等于5时,执行break语句,结束整个循环,接着执行循环后续的代码。
与C/C++不同,Java 提供了一种带标签的break 语句,用于跳出标号标识的循环。这种break语句多用于跳出多重嵌套的循环语句,适合需要中断外部的循环,即采用标签语句来标识循环的位置,然后跳出标签对应的循环。示例代码片段如下:
label1:
for(int i = 0; i < 10 ; i++){
System.out.println(j);
if(j==3){
break label1;//中断外部循环
}
}
这里的label1是标签的名称,可以用任意的标识符定义,放在对应的循环语句上面,以冒号结束。在该示例代码中,label1在外循环上面,将会中断外循环,实现时在需要中断循环的位置,采用break后面跟着标签。
2、continue语句
continue语句必须用于循环结构中,功能是跳过该次循环,继续执行下一次循环。在while和do-while语句中,continue 语句跳转到循环条件处开始继续执行,而在for语句中,continue 语句跳转到for语句处开始继续执行。和break语句类似,continue 语句也有两种使用格式:不带标签的continue语句和带标签的continue语句,不带标签的continue语句将终止当前这一轮的循环,不执行本轮循环的后一部分,直接进入当前循环的下一轮。下面以while 语句为例,说明不带标签的continue语句用法,代码片段如下:
int i = 0;
while(i < 4){
i++;
if(i == 2){
continue;
}
System.out.println(i);
}
在i值等于2时,执行continue语句,则后面未执行完的循环体将被跳过,不会执行System.out.println(2); 而是直接回到while 处,进入下一次循环,所以打印结果没有2。
带标签的continue语句将使程序跳出多重嵌套的循环语句,直接跳转到标签标明的循环层次,标签必须放置在最外层的循环之前,紧跟一个冒号。 和break类似,这种语句用于跳过外部的循环,需要使用标签来标识对应的循环结构,代码片段如下:
label1:
for(int i = 0; i < 10 ; i++){
for(int j = 0; j < 5; j++){
System.out.println(j);
if(j == 3){
continue label1;
}
}
}//在执行continue语句时,直接跳转到i++语句,而不执行j++
3、return语句
return语句总用在方法之中,有如下两个作用
1️⃣ 返回方法指定类型的值,格式为:return 表达式;
2️⃣ 结束方法的执行并返回至调用这个方法的位置,格式为:return;
(2) 异常处理
1) 异常的分类与组织架构
Java API的每个类库包中几乎都定义有异常类,如图形用户界面AWTException、输入/输出异常类IOException、数据库异常类sQLException.运行时异常类RuntimeException、算术运算异常类ArithmeticException等。
javalang 下的Throwable类是所有异常和错误的父类,它包含两个子类Error和Excption,分别表示错误和异常
错误Error类用于处理致命性的、用户程序无法处理的系统程序错误,如硬件故障、虚拟机运行时错误(VritualMachineError)、线程死亡(ThreadDeath).动态链接失败( Linkagerror),这些错误用户程序是不需要关注的,一旦运行时出错,就由系统自动报错
Error类和Exception类的继承关系如下:
Java 的异常类总体上可以分为两类:非检查型异常( non-checked exception) 和检查型异常(checked exception)。
非检查型异常继承自RuntimeException运行时异常,这类异常是不需要检测的,由系统自动检测出异常,自动报错,提供默认的异常处理程序。程序中可以选择捕获处理,也可以不处理。这类异常一般是由程序逻辑错误引起的,应该从逻辑角度尽可能避免这类异常的
发生,常见的如数组越界、除零等。常用的非检查型异常继承关系如下:
检查型异常要求用户程序必须处理,属于Exception类及其子类,需要手动标示在什么位置可能出现异常、如何捕获异常以及如何处理。常用的检查型异常继承关系如下:
2)异常的声明与处理
Java的异常处理机制是如何工作的呢?无论是检查型异常还是非检查型异常,针对可能出现的异常,用户程序必须从以下两种处理方式中做出选择:
1 ) 在异常出现的方法中主动用try…catch句型处理。
2) 如果该方法中没有做出任何处理,就把异常抛给调用该方法的上一层方法,如果上一层方法由try-catch句型处理了,则到此为止,否则继续顺着方法调用的层次逐级向上抛出,沿着被调用的顺序往前寻找,直到找到符合该异常种类的处理程序,交给这部分程序处理,如
果抛到了程序调用顶层,main() 还没有被处理,则程序执行停止,main() 方法发出错误信息。
非检查型异常处理
非检查型异常属于系统定义的运行异常,由系统自动检测并做出默认处理,用户程序不必做任何事情
举例:处理数组越界出现的异常
public class TestException_1 {
//处理数组越界出现的异常
public static void main(String[] args) {
int a[]=new int[5];
a[6]=5;
}
}
运行结果:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 5
at com.xjtu.chapter06.TestException_1.main(TestException_1.java:12)
检查型异常处理
对于检查型异常,Java要求用户程序必须进行处理,根据具体情况判断在代码段何处处理异常,处理方式包括两种:捕获异常和声明抛出异常。对于前者,使用try-catch语句,捕获到发生的异常,并进行相应的处理;对于后者,不在当前方法内处理异常,而是把异常抛出到调用方法中由上层方法处理
1️⃣ 捕获异常
这种处理方式通常是在发生异常的方法内捕获该异常,并立即进行处理,语法格式如下:
try{
statement() //可能产生异常的代码块
}catch(exceptiontype objectname){
statement() //处理代码块
}
finally{
statement() //必须执行的代码
}
将可能产生异常的代码块放在try{中,每个try语句必须伴随一个或多个catch语句,用于捕获try 代码块产生的异常并做相应的处理。catch语句可以接受一个参数,即异常类型的对象,exceptiontype必须是一个从Throwable类派生出来的异常类的类型。
有时,需要执行finally语句,finally语句用于执行收尾工作,为异常处理提供一个统一的出口。无论程序是否抛出异常,也无论catch捕获到的异常是否正确,finally 指定的代码都要被执行,并且这个语句总是在方法返回前执行,目的是给程序一个补救的机会。通常在finally语句中可以清除除了内存以外的其他资源,如关闭打开的文件、删除临时文件等。
注意事项: try、catch、finally三个语句块必须组合起来使用,三者可以组成try…catch…finally、try …catch和 try…finally三种结构,catch语句可以有一个或多个,finally语句最多一个。异常处理的查找遵循类型匹配原则,一个异常在匹配到其中一种异常类型后接着执行catch 块代码,一旦第一个匹配的异常处理被执行,则不会再执行后面的catch块。异常处理执行完毕,程序接着最后一个catch代码段后的语句继续执行。
2️⃣ 声明抛出异常
在一个方法中生成了异常,但是该方法并不采用try-catch语句处理产生的异常,而是沿着调用层次向上传递,交给调用它的上一层方法来处理,这就是声明抛出异常。
声明抛出异常的方法是在产生异常的方法名后面加上关键字throws,后面接上所有可能产生异常的异常类型,语法格式如下:
void func() throws ExceptionA,ExceptionB,ExceptionC{
......
}
3)自定义异常
原则上,异常处理的过程应该分为三步:首先,将产生异常的代码段放在try{}里,然后抛出(throw)异常,最后捕获(catch) 异常。前面提到的try-catch方式,实际上省略了其中的抛出步骤,try-catch 方式处理的异常通常由Java JVM产生,或者由Java类库中的某些异常类产生,然后隐式地在程序里被抛出,JVM已经替程序完成了抛出异常的操作,而程序中只需执行try和catch两步即可。
然而,有些情形下三个步骤是缺一不可的,例如程序中仅仅使用Java类库提供的异常类不能够满足要求时,需要自己定义异常类,当然这些异常JVM是不可能识别的,只能由用户程序手动引发,通过new生成自定义的异常对象,然后将它抛出来(注意:这里是throw而不是throws)。throw 语法格式如下:
throw new ThrowableObject();
或者先自定义一个异常类,然后抛出其对象:
myException e = new myException();
throw e;
抛出的异常必须是Throwable或其子类的对象,throw语句常用于异常产生语句块中,与try-catch语句配合使用。
throws与throw仅一个字母的差别,却是两种完全不同的概念。throws写在方法的后面,抛出异常交给上级方法或类,即抛给调用它的方法进一步处理; 而throw多用来抛出自定义的异常类对象,这类异常必须是Throwable类的子类,需要用户自己手工进行捕获。
首先看看程序中如果显式地将Java类库提供的异常类对象通过throw抛出,这有助于理解异常处理的三个步骤。
举例:使用try,throw,catch处理三种情形:无异常、除数为零、数组越界可能产生的异常
public class Process {
void Proc(int sel){
System.out.println("******in case "+sel+" ******");
if(sel==0){
//没有异常
System.out.println("no exception caught");
return;
}else if(sel==1){
try{
int i=0;
int j=5/i;//除数为零
throw new ArithmeticException();//显式地抛出ArithmeticException异常对象
}catch (ArithmeticException e){
System.out.println(e.toString());
}
}else if(sel==2){
try{
int array[] = new int[4];
array[5]=5;
throw new ArrayIndexOutOfBoundsException();//显式地抛出ArrayIndexOutOfBoundsExceptionn异常对象
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e.toString());
}
}
}
}
public class Test {
public static void main(String[] args) {
Process process = new Process();
try{
process.Proc(0);//调用Proc
process.Proc(1);
process.Proc(2);
}catch (ArithmeticException e){
System.out.println("catch: "+ e+";Reason: "+e.getMessage());
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("catch: "+ e+";Reason: "+e.getMessage());
}catch (Exception e){
System.out.println("Will not be executed");
}finally {
System.out.println("must go inside finally");
}
}
}
运行结果:
******in case 0 ******
no exception caught
******in case 1 ******
java.lang.ArithmeticException: / by zero
******in case 2 ******
java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 4
must go inside finally
此例中一旦有异常产生,就创建异常类ArithmeticException或者ArrayIndexOutOfBoundsException对象,并执行throw new ArithmeticException()语句抛出一个ArithmeticException类异常对象,或者执行throw new ArrayIndexOutOfBoundsException(语句抛出ArrayIndexOutOfBoundsException类异常对象。一 般而言,当抛出Java类库定义的异常时,JVM会自动识别,程序里往往可以省略throw步骤。
如何抛出一个自定义的异常类对象?Java允许用户自行设计异常类,以便处理运行中可能出现的逻辑错误。比如学生年龄为20是-一个整数,如果不小心给学生年龄赋值为200,编译时不会有语法错误,但不符合常识,这时,可以自定义一个AgeException异常类来表示这种异常。在软件开发中,需要自定义异常类的情形有很多,尤其是大型项目开发,开发人员通常预定义好一些异常类,这些异常类可以如同Java类库的异常类一样使用,方便项目组同事共享,在有异常隐患的程序中调用,以提高项目的整体稳定性及协调性。声明自己的异常时,所有异常类都必须是Exception的子类,声明格式如下:
class MyException extends SuperclassOfException{
...
}
其中SuperclassOfException可以为Exception、ArithmeticException、 IOException…
举例:以电子产品商店为例,假设产品价格少于100元则不合理,自定义一个异常类如下:
public class PriceException extends Exception {
public PriceException(){
System.out.println("the price is less than 100 yuan ,too low!");
}
}
测试类如下:
public class TestPriceException {
public static void main(String[] args) {
Product product = new Product();
product.productPrice = 20;
try {
if(product.productPrice<100) throw new PriceException();
} catch (PriceException e) {
e.getMessage();
}
}
}
运行结果如下:
the price is less than 100 yuan ,too low!
在main()中创建了一个product对象,其价格为20,在try块中判断ProductPrice的价格,小于100,则抛出自定义的PriceException对象,紧跟着的catch语句捕获到对象e后,调用构造方法输出错误信息。
编程提示:程序里尽可能多地使用异常处理机制,在后面的学习中,每一项新内容都应学会使用类库提供的异常处理方法,比如学习JDBC则应学会使用SQLException。