11-1,Object类-equals方法
1,Object是所有类的根类。
Object是不断向上抽取而来的,具备着所有对象都具备的共性的内容。
2,equals方法:指示其他某个对象是否与此对象相等。equals(Object obj)。
equals方法比较的是两个对象的地址值。
他在Java中的源代码为:
public boolean equals(Object obj) {
return this == obj;
}
调用格式为obj1.equals(obj2);
如:
Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;
System.out.println(p1 == p2);
System.out.println(p1.equals(p3));
11-2,equals方法覆盖
1,开发时一般都会覆盖equals方法,因为值判断地址值没有太大意义。
根据对象的特有内容,建立判断对象是否相等的依据。
如:
比较两个人的年龄是否相同:
public boolean equals(Object obj) {
if(!(obj instanceof Person)) { //判断obj是否是Person类型
throw new ClassCastException("类型错误");//如果不是Person类型,则不能向下转型
}
Person p = (Person)obj; //向下转型后才能使用子类中的特有内容
return this.age == p.age;
}
这里因为用Object obj接收参数,相当于Object obj = p;把p2向上转型为Object类型,p2里面的特有内容不能使用。
11-3,Object类-hashCode方法
1,作用:返回该对象的散列码值(哈希码)。
2,Person p = new Person();
System.out.println(p.hashCode()); //打印十进制的哈希值
3,验证哈希码是否相同
Person p1 = new Person(20);
System.out.println(p1);
System.out.println(Integer.toHexString(p1.hashCode()));//把十进制的哈希值转成十六进制
11-4,Object类-getClass方法
1,作用:返回此Object的运行时类。
Person p1 = new Person();
Person p2 = new Person();
Class clazz1 = p1.getClass();
Class clazz2 = p2.getClass();
//比较获取的字节码文件的内存地址,由于p1和p2都是由Person创建的,所以地址相同
System.out.println(clazz1 == clazz2); //true
//返回字节码文件的名称
System.out.println(clazz1.getName()); //Person
以上例来说,Person类加载创建了Person.class文件,这个文件就是Person类以后创建对象的顶层字节码文件,Person.class字节码文件在内存中有且只有一个,p1和p2这些对象都是依据Person.class文件创建的。
getClass方法返回的就是这样的字节码文件。
11-5,Object类-toString方法
1,作用:返回该对象的字符串表示。
2,Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1);//Person@616d63
System.out.println(p1.getClass().getName+ "$"+Integer.toHexString(p1.hashCode()));//Person$616d63
3,Object类的toString方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at标记符@和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:getClass().getName()+"@"+Integer.toHexString(hashCode());
4,为了实际应用,通常在子类中重写equals、hashCode和toString方法。
如:
public String toString() {
return "Person : " + age;
}
11-6,异常-概述
1,异常:是在运行时间发生一些不正常的情况。
在Java中用类的形式对不正常的情况进行了描述和封装对象。
描述不正常的情况的类,就称为异常类。
以前正常的流程代码和问题处理代码相结合,现在将正常流程代码和问题处理代码分离,提高了阅读性。
其实异常就是Java通过面向对象的思想将问题封装成了对象。
用异常类对其进行描述。
不同的问题用不同的类进行具体的描述。比如角标越界,空指针等。
旧方法与新方法的比较:
class ExceptionDemo {
public static void main(String[] args) {
int[] arr = new int[3];
arr = null;
System.out.println(arr[3]);//抛出指向为空的异常,若没有arr=null则抛出角标越界异常
sleep(-5); //若时间为负或大于10000,则抛出异常。
}
public static void sleep(int time) {
/* 原始解决办法,正常流程代码和问题处理代码相结合
if(time < 0) {
处理办法...
}
if(time > 10000) {
处理办法...
}
System.out.println("我睡" + time);
*/
//抛出异常的处理办法,正常流程代码和问题处理代码相分离
//代码时间为负的情况,这个FuTime对象中会包含异常的名称,信息,位置等信息。
if(time < 0) {
抛出 new FuTime();
}
if(time > 10000) {
抛出 new BigTime();
}
System.out.println("我睡" + time);
}
}
//定义异常解决办法的类
class FuTime {
处理办法...
}
class BigTime {
处理办法...
}
11-7,异常体系
1,Java中有很多异常,每一个异常都是一个类。问题很多,意味着描述他的类也很多,将其共性向上抽取,就形成了异常体系。
2,最终问题分为两大类:
(1)一般不可处理的,用Error类表示。
(2)可以处理的,用Exception类表示。
Throwable
|--Error
|--Exception
无论是Error还是Exception,问题发生就应该可以抛出,让调用这知道并处理。该体系的特点就在于Throwable及其所有的子类都具有可抛性。
3,可抛性到底指的是什么呢?怎样体现可抛性呢?
是通过两个关键字来体现的,就是throws和throw,凡是可以被这两个关键字所操作的类和对象都具备可抛性。
4,Error的特点为:
是由JVM抛出的严重性的问题,这种问题发生一般不针对性处理,直接修改程序。
5,该体系的特点:
子类的后缀名都是用其父类名作为后缀,阅读性很强。
11-8,异常-原理&异常对象的抛出throw
1,异常抛出过程,用下面程序为例说明:
class Demo {
public void method(int[] arr, int index) {
/* 第一步:
这一句会抛出一个异常
throw new ArrayIndexOutOfBoundsException(index);
这个抛出动作由JVM自动执行,运行到此处,发现角标越界,便抛出此异常
抛给调用者,即主函数,抛出异常后,这个方法结束,不再输出haha。
*/
System.out.println(arr[index]);
System.out.println("haha");
}
}
class ExceptionDemo {
public static void main(String[] args) {
int[] arr = new int[3];
Demo d = new Demo();
/* 第二步:
throw new ArrayIndexOutOfBoundsException(index);
调用者主函数接收抛出的异常,继续向上抛出,抛给JVM,抛出后不再输出over。
*/
d.method(arr,3);
System.out.println("over");
}
}
第三步:
JVM的处理方式为:在控制台输出异常信息,反馈给用户,程序结束。
2,自定义异常抛出信息。
系统自带的抛出信息为英文,有时会在成阅读不便。故自定义信息,使其简明易懂。
class Demo {
public int method(int[] arr, int index) {
if(arr == null)
throw new NullPointerException("数组的引用不能为空!");
if(index >= arr.length)
throw new ArrayIndexOutOfBoundsException("数组角标越界!" + index);
if(index < 0)
throw new ArrayIndexOutOfBoundsException("数组角标不能为负数:" + index);
return arr[index];
}
}
class ExceptionDemo {
public static void main(String[] args) {
int[] arr = new int[3];
Demo d = new Demo();
int num = d.method(null,-30);
System.out.println("num = " + num);
System.out.println("over");
}
}
使用throw关键字抛出异常。
11-9,异常-自定义异常&异常类的抛出
1,对于角标是正数不存在,可以用角标越界表示。
对于角标为负数的情况,准备用复数角标异常来表示。
负数角标这种异常在Java中并没有定义过,那就按照Java异常的创建思想,面向对象,将服输角标进行自定义描述,并封装成对象。
这种自定义的问题描述称为自定义异常。
注意:如果让一个类称为异常类,必须要继承异常体系,因为只有称为异常体系的子类才有资格具备可抛性,才可以被两个关键字所操作,throws和throw。
2,若要成为异常类,必须继承Exception类,并在产生此异常的方法后加上throws 异常类名。
调用此方法的语句的所属的方法也要加上throws 异常类名。
示例:
//自定义异常类必须继承Exception类,才具备可抛性
class FuShuIndexException extends Exception {
FuShuIndexException() {}
FuShuIndexException(Stirng msg) {
super(msg);//用的是父类的构造方法,传参数调用
}
}
class Demo {
//在方法上throws声明这个方法可能抛出的异常
public int method(int[] arr, int index) throws FuShuIndexException {
if(index < 0) {
throw new FuShuIndexException("角标不能是负数!");
}
return arr[index];
}
}
class ExceptionDemo {
//调用了可能抛出异常的方法,调用他的方法也要抛出异常
public static void main(String[] args)throws FuShuIndexException {
int[] arr = new int[3];
Demo d = new Demo();
int num = d.method(arr,-30);//此语句可能抛出异常
System.out.println("num : " + num);
}
}
11-10,异常-编译时检测异常和运行时异常的区别&throw和throws的区别
1,异常的分类:
(1)编译时被检测异常,只要是Exception和其子类都是,除了特殊子类RuntimeException体系这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。这样的问题都可以针对性的处理。
(2)编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类,这种问题的发生,无法让功能继续,运算无法进行,更多是因为调用者的原因导致的,或者是引发了内部状态变化而导致的。那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行修正。
所以自定义异常类时,要么继承Exception,要么继承RuntimeException。
2,throw和throws的区别。
(1)throws使用在函数上。
throw使用在函数内。
(2)throws抛出的是异常类,可以抛出多个,用逗号隔开。
throw抛出的是异常对象。
3,11-9的例子中,若写为:
Class FuShuIndexException extendsRuntimeException,则Demo类中的方法和ExceptionDemo中的main方法就不用throw FuShuIndexException了。
11-11,异常-异常捕获try-catch
1,异常处理的捕捉形式:
这是可以对异常进行针对性处理的方式。
具体格式是:
try{
//需要被检测异常的代码
} catch(异常类 变量) { //该变量用于接收发生的异常对象
//处理异常的代码
} finally {
//一定会被执行的代码
}
示例:
class ExceptionDemo {
public static void main(String[] args) {
int[] arr = new int[3];
Demo d = new Demo();
try {
int num = d.method(arr, -1);
/*
由于num是局部变量,出了作用域便不可用,如后面的代码用到此变量
也要放到try中。
*/
System.out.println("num=" + num);
} catch(FuShuIndexException e) { //接收的是什么异常,此处就写什么异常类。
System.out.println("message:" + e.getMessage());//打印异常信息
//打印e的信息,格式为:异常名:信息,toString可以不写。
System.out.println("string:" + e.toString());
/*
void类型的方法,不能在sop中输出。此方法输出异常的名称,信息,位置等,
等同于throw出的异常信息,JVM默认的处理机制就是调用异常对象的这个方法。
*/
e.printStackTrace();
System.out.println("负数角标异常");
}
System.out.println("over");
}
}
class Demo {
//抛出此异常,catch中也应该接受此异常处理要有针对性。
public int method(int[] arr, int index) throws FuShuIndexException {
if(index < 0) {
throw new FuShuIndexException("角标不能是负数");
}
return arr[index];
}
}
2,捕捉过程
步骤:
(1)调用method方法时,method方法声明了抛出的异常,传入的-30满足index<0的条件,用throw抛出了异常,抛给main中的调用者,调用者用trycatch对异常进行了解决。
(2)满足index<0抛出异常。
(3)由于用trycatch形式处理异常,会直接在catch中解决,输出”负数角标异常”,之后的”over”也输出。
11-12,异常-多catch情况
throws声明异常可以有多个,用逗号隔开,用下例说明:
class FuShuIndexException extends Exception {
FuShuIndexException() {}
FuShuIndexException(String msg) {
super(msg);
}
}
class Demo {
public int method(int[] arr, int index) throws NullPointerException,FuShuIndexException {
if(arr == null)
throw new NullPointerException("没有任何数组实体");
if(index < 0)
throw new FuShuIndexException();
return arr[index];
}
}
class ExceptionDemo {
public static void main(String[] args) {
int[] arr = new int[3];
Demo d = new Demo();
try {
//在try后面,一般都先执行第一个catch,若Exception在最上面,则其他catch白写。
int num = d.method(null, -1);
System.out.println("num = " + num);
} catch(NullPointerException e) {
System.out.println(e.toString());
} catch(FuShuIndexException e) {
System.out.println("message:" + e.getMessage());
System.out.println("String:" + e.toString());
e.printStackTrace();
System.out.println("负数角标异常");
} catch(Exception e) {}
/*
多catch情况,父类的catch放在最下面
Exception是所有异常类的父类,若可能有抛出的以外的其他异常的情况发生,
需要使用Exception解决时,Exception必须放在最下面。
*/
System.out.println("over");
}
}
11-13,异常处理原则
1,原则:
(1)函数内部如果抛出需要检测的异常,那么函数上必须声明。否则必须在函数内使用trycatch捕捉,否则编译失败。
(2)如果调用了声明异常的函数,要么trycatch要么throws,否则编译失败。
(3)什么时候用catch,什么时候用throws呢?
功能内部可以解决用catch;
解决不了,用throws告诉调用者,由调用者解决。
(4)一个功能如果抛出了多个异常,那么调用时,必须有对应的多个catch进行针对性的处理。内部有几个需要检测的异常,就抛出几个异常,抛出几个就catch几个。
11-14,异常-finally代码块
1,finally通常用于关闭(释放)资源,以下例说明,finally不管怎样都会执行,但若在finally前使用了System.exit(0);则finally不执行,System.exit(0);直接退出了JVM。
class Demo {
public int show(int index) throws ArrayIndexOutOfBoundsException {
if(index < 0)
throw new ArrayIndexOutOfBoundsException("角标越界");
int[] arr = new int[3];
return arr[index];
}
}
class ExceptionDemo {
public static void main(String[] args) {
Demo d = new Demo();
try {
int num = d.show(-1);
System.out.println("num:" + num);
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println(e.toString());
//return;退出main函数,只输出e.toString()和finally中的内容
//System.exit(0);退出JVM,只输出e.toString()
} finally {//通常用于关闭(释放)资源
System.out.println("finally");
}
System.out.println("over");
}
}
2,例如:
连接数据库
查询:抛出异常Exception
关闭连接
在连接数据库后,进行查询的时候抛出了异常,若没有finally去结束链接,则数据库不会断开连接,会占用大量资源。Finally是无论怎样都会执行的代码块,若在抛出异常后,在finally中结束链接,则会释放资源。
3,try,catch,finally代码的组合特点
(1)try-catch-finally常规组合
(2)try catch(多个)
当没有必要资源需要释放的时候,可以不定一finally。
(3)try-finally
异常无法直接用catch处理,但是资源需要关闭时使用。
如:
void show() throws Exception { //方法中有抛出异常,需要声明
try{
//开启资源
//抛出异常后无法正常关闭资源,用finally关闭,这个异常无法用catch直接处理
throw new Exception();
} finally {
//关闭资源
}
}
11-15,异常应用
需求:老师用电脑上课
这个问题涉及两个对象,老师和电脑。
其中可能产生的问题:比如电脑蓝屏,冒烟,没响应。
//首先定义三个异常类
class LanPingException extends Exception {
LanPingException() {}
LanPingException(String msg) {
super(msg);
}
}
class MaoYanException extends Exception {
MaoYanException() {}
MaoYanException(String msg) {
super(msg);
}
}
class NoPlanException extends Exception {
NoPlanException() {}
NoPlanException(String msg) {
super(msg);
}
}
class Computer {
//初始化状态,0表示正常,1表示蓝屏,2表示冒烟
private state = 0;
public void run() throws LanPingException,MaoYanException {
if(state == 1)
throw new LanPingException("电脑蓝屏了!");
if(state == 2)
throw new MaoYanException("电脑冒烟了!");
System.out.println("电脑运行");
}
public void reset() {
state = 0;
System.out.println("电脑重启");
}
}
class Teacher {
private String name;
private Computer comp;
Teacher(String name) {
this.name = name;
//老师携带电脑,在初始化时创建Computer对象
comp = new Computer();
}
//捕获的冒烟异常中抛出了此异常
public void prelect() throws NoPlanException {
try {
comp.run();
System.out.println(name + "讲课");
} catch(LanPingException e) {
System.out.println(e.toString());
comp.reset();
prelect();
} catch(MaoYanException e) {
System.out.println(e.toString());
test();
throw new NoPlanException("课时进度无法完成,原因:" + e.getMessage());
/*
这里虽然抛出的是冒烟异常,但是抛出后上级无法解决,所以抛出计划无法完成异常,
让上级能够解决。抛出异常和声明异常应根据实际情况而定。
*/
}
}
public void test() {
System.out.println("大家练习");
}
}
class ExceptionTest {
public static void main(String[] args) {
Teacher t = new Teacher("老师");
try {
t.prelect();
} catch(NoPlanException e) {
System.out.println(e.toString() + "...");
System.out.println("换老师");
}
}
}