七、抽象类与接口
1、抽象类
- 抽象类不能实例化,只能被继承,继承后才能使用
- 修饰符不能为private(private不能被子类继承)
(1)抽象方法
- 一种抽象的方法,比如动物的吃、喝、玩等行为,子类继承后会对这类行为进行具体描述。
- 子类必须重写父类抽象方法,或者自身为抽象类
abstract void method();
(2)抽象类使用案例
abstract class Son{
public abstract void abstract_method();
}
public class Father extends Son{
@Override
public void abstract_method() {
System.out.println("新方法");
}
public void method(){
System.out.println("非抽象方法");
}
public static void main(String[] args) {
Son s = new Father();//向上转型,使用父类的功能就能完成相应的操作
s.abstract_method();//新方法
//s.method();//父类没有这个功能
Father fa =new Father();
fa.abstract_method();//新方法
fa.method();//子类特有方法
}
}
注意:
- 一个java文件里类前面的public只能出现一个,public说明是公共的,比如案例中
public class Father
已经存在了,就不能abstract class Son
了 - 注意向上转型时子类的功能,父类中有时没有
2、接口
(1)接口的实现
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
- 一个类可以同时实现多个接口。
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
//Father.java 文件
interface File {
public void write();//文件接口写入方法
public void read();//文件接口读出方法
}
interface Music extends File{
public void recording(String name);//Music接口继承自File接口,录音recording是特有方法
}
interface Sava {
public int willSave(int num);
}
public class Father implements Music,Sava{
public void write() {
System.out.println("我会写");
} //重载willEat()
public void read() {
System.out.println("我会读");
}
public void recording(String name) {
System.out.println(name);
}
public int willSave(int num) {
return num;
}
public static void main(String[] args) {
Father fa = new Father();
fa.read();//我会读
fa.write();//我会写
fa.recording("s");//s
System.out.println(fa.willSave(5));//5
}
}
(2)接口的继承
接口也可以被其他接口继承,一个接口可以继承多个接口
// 文件名: Sports.java
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
另一个文件里的接口继承Sports接口
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
Hockey接口需要实现六个方法,包括自己声明的四个方法,从Sports接口继承了两个方法。
八、异常处理
1、异常分类
- Error:运行时环境发生的错误
- Exception:程序运行中产生的异常,包括Runtime异常和非Runtime异常。
Runtime异常包括:
(1)数组下标越界异常(IndexOutOfBoundsException)
(2)空指针异常(NullPointerException)
(3)对象类型强制转换异常(ClassCastException)
(4)数组存储异常(ArrayStoreException,即数组存储类型不一致)等
非Runtime异常包括:
(1)IOException
(2)SqlException
2、异常处理过程
(1)try-catch
try:可能抛出异常的代码)放在try语句块之内
catch:用来捕获try语句块中发生的异常
try {
...
} catch (IOException ioException) {
...
}
案例 空指针异常
int[] arr = {1, 2, 3};
//访问数组中的元素
try {
arr = null;
//System.out.println(arr[3]);
System.out.println(arr[1]);
} catch (NullPointerException e) {
System.out.println("发生了空指针异常");
// 处理异常
}
//输出发生了空指针异常
(2)try-catch-finally
public static void main(String[] args) {
int[] arr = {1, 2, 3};
//访问数组中的元素
try {
System.out.println(arr[3]);
} catch (NullPointerException e) {
System.out.println("发生了空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("发生了数组越界异常" +e);
} catch (Exception e) {
e.printStackTrace();
} finally {//不管多少异常都能执行
System.out.println("请仔细检查错误");
}
System.out.println("运行完毕");
}
/*
发生了数组越界异常java.lang.ArrayIndexOutOfBoundsException: 3
请仔细检查错误
运行完毕
*/
无论是否发生异常,finally 代码块中的代码总会被执行。良好的编程习惯是:在try块中打开资源,在catch中处理错误,在finally块中清理并释放这些资源,以免造成内存泄露。
(3)throws/throw
- throw:在某些场景下,使用 throw 关键字抛出一个异常,可以用来规范一些行为或者输入,若输入不规范则报错
public static void save(String user) {
if (user == null)
throw new IllegalArgumentException("User对象为空");
}
public static void main(String[] args) {
try {
throw new ArrayIndexOutOfBoundsException("数组越界啦");
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界!!!!!!!");
System.out.println("异常:" + e);
}
save(null);//直接报错
}
/*
数组越界!!!!!!!
异常:java.lang.ArrayIndexOutOfBoundsException: 数组越界啦
Exception in thread "main" java.lang.IllegalArgumentException: User对象为空
*/
- throws:throws 声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由向上一级的调用者处理
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// 方法内容
}
案例:方法save()
抛出错误,由main函数处理
public static void save(String user) throws IllegalArgumentException{
if (user == null)
throw new IllegalArgumentException("User对象为空");
}
public static void main(String[] args) {
try {
save(null);
}catch (IllegalArgumentException e){
System.out.println("主函数来处理这个异常了");
}
//主函数来处理这个异常了
}
(3)面试题案例:
public static void main(String[] args) {
int result = test1();
System.out.println(result);
}
public static int test1() {
int i = 1;
try {
i++;
System.out.println("try block, i = " + i);
} catch (Exception e) {
i--;
System.out.println("catch block i = " + i);
} finally {
i = 10;
System.out.println("finally block i = " + i);
}
return i;
}
/*
try block, i = 2
finally block i = 10
10
*/
3、自定义异常
- 所有异常都必须是 Throwable 的子类
- 自定义写一个检查性异常类,则需要继承 Exception 类
- 自定义一个运行时异常类,那么需要继承 RuntimeException 类
案例:
//自定义异常类,继承Exception类
class MyException extends Exception
{
//此处的amount用来储存当出现异常时的数量
private double amount;
public MyException(double amount)//重写构造方法
{
this.amount = amount;
}
// public MyException(String s) {
// super(s);
// }
public double getAmount()
{
return amount;
}
}
public class Father {
public static void save(double amount) throws MyException{
if (amount ==0.0)
throw new MyException(amount);
}
public static void main(String[] args) {
try {
save(0.0);
}catch (MyException e){
System.out.println("余额不足了:"+e.getAmount());
}
//主函数来处理这个异常了
}
}
/*
余额不足了:0.0
*/