面向对象核心技术

一、抽象类与接口

1.抽象类

假设我们并不希望新建的类的对象会被创建出来,那么我们就把该新建的类定义为抽象的。我们用abstract关键字来定义抽象类。抽象类的作用仅仅是表达接口,而不是具体的实现细节。抽象类中可以有抽象方法且该方法也由关键字abstract关键字进行修饰。抽象的方法是不完全的,它只是一个方法签名而完全没有方法体
注意:

  1. 如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。
  2. 如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法,否则子类也成为一个抽象类。
  3. 一个抽象类可以没有任何一个抽象方法,所有的方法都有方法体,但是整个类是抽象的。设计这样的抽象类主要是为了防止制造它的对象出来。

2.接口

接口其实就是完全的抽象类,因此接口和类的地位是一样的。接口所有的方法都是没有方法体的且都是public abstract,即使不声明。而接口中的所有成员变量都是public static final的变量,并且必须有定义初始化,因为所有变量都必须在编译的时候有确定的值。Java用一个动词:实现(implements)关键字进行修饰接口。实现接口的类必须覆盖接口的所有方法,否则这个类就会成为一个抽象类。Java=不允许多继承,但允许一个类实现多个接口得到继承,但是不允许接口从类继承。

3.抽象类与接口的对比

参数抽象类接口
默认的方法实现它可以有默认的方法实现接口完全是抽象的。它根本不存在方法的实现
实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
访问修饰符抽象方法可以有public、protected和default这些修饰符接口方法默认修饰符是public。你不可以使用其它修饰符。

4.github练习题

实例1:使用抽象类模拟"去商场买衣服"场景

abstract class Market{//定义一个抽象类实现具体是什么商场、买什么东西
    public String name;//商场名称
    public String goods;//商品名称

    public abstract void shop();//抽象方法,用来输出信息
}

//定义一个TaobaoMarket继承自Market抽象类,实现其中的shop()抽象方法
class TaobaoMarket extends Market{
    public void shop(){
        System.out.println(name+"网购"+goods);
    }
}

//定义一个WallMarket类,继承自Market抽象类,实现其中的shop()抽象方法
class WallMarket extends Market{
    public void shop(){
        System.out.println(name+"实体店购买"+goods);
    }
}

//创建WallMarket类与TaobaoMarket类创建抽象类的对象,并分别给抽象类中的成员变量赋不同的值
public class GoShopping {
    public static void main(String[] args){
        Market market=new WallMarket();//使用派生类对象创建抽象类对象
        market.name="沃尔玛";
        market.goods="七匹狼西服";
        market.shop();
        market=new TaobaoMarket();//使用派生类对象穿件抽象类对象
        market.name="淘宝";
        market.goods="韩度衣舍花裙";
        market.shop();
    }
}

代码运行结果:
在这里插入图片描述
练习1:创建 Shape(图形)类,该类中有一个计算面积的方法。圆形和矩形都继承自图形类,输出圆形和矩形的面积。

abstract class Shape{//定义一个形状的抽象类
    public double r;//圆的半径
    public double a;//长方形的长
    public double b;//长方形的宽

    public abstract void area();//抽象方法用来输出信息
}

//定义一个CfxArea类继承Shape抽象类,实现其中的area方法
class CfxArea extends Shape{
    public void area(){
        System.out.println("长为"+a+"宽为"+b+"的长方形的面积是:"+(a*b));
    }
}

//定义一个CircleArea类继承Shape抽象类,实现其中的area方法
class CircleArea extends Shape{
    public void area(){
        System.out.println("半径为"+r+"的圆的面积为:"+(r*r*3.14));
    }
}

public class Area {
    public static void main(String args[]){
        Shape area=new CfxArea();//使用派生类对象创建抽象类对象
        area.a=7.2;
        area.b=10;
        area.area();
        area=new CircleArea();//使用派生类对象创建抽象类对象
        area.r=20;
        area.area();
    }
}

运行结果截图:
在这里插入图片描述
练习2:创建工厂类,工厂类中有一个抽象的生产方法,创建汽车厂和鞋厂类,重写工厂类中的抽象生产方法,输出汽车厂生产的是汽车,鞋厂生产的是鞋。

abstract class BigFactory{//创建抽象大工程类
    public abstract void bigfactory();//构造抽象方法用来输出信息
}

//构造Car类继承BigFactory类
class Car extends BigFactory{
    public void bigfactory(){
        System.out.println("汽车工厂生产汽车");
    }
}

//构造Shose类继承BigFactor类
class Shose extends BigFactory{
    public void bigfactory(){
        System.out.println("制鞋工厂生产鞋");
    }
}

public class Factory {
    public static void main(String args[]){
        BigFactory factory=new Car();
        factory.bigfactory();
        factory=new Shose();
        factory.bigfactory();
    }
}

代码运行截图:
在这里插入图片描述
实例2:通过实现接口 绘制出特殊的平行四边形

interface DrawImage{//定义“画图形”接口
    public void draw();//定义抽象方法“画”
}

class Rectangle implements DrawImage{//矩形实现了drawTest接口
    public void draw(){
        System.out.println("画矩形");
    }
}

class Square implements DrawImage{
    public void draw(){
        System.out.println("画正方形");
    }
}

class Diamond implements DrawImage{
    public void draw(){
        System.out.println("画菱形");
    }
}

public class SpecialParallelogram {//定义特殊的平行四边形类
    public static void main(String args[]){
        //接口也可以进行行傻瓜转型操作
        DrawImage[] images={new Rectangle(),new Square(),new Diamond()};
        //遍历“画图形”接口类型的数组
        for (int i=0;i<images.length;i++){
            images[i].draw();//调用draw()方法
        }
    }
}

运行代码截图:
在这里插入图片描述
实例3: 爸爸喜欢做的事有抽烟和钓鱼,妈妈喜欢做的事有看电视和做饭,儿子完全继承了爸爸妈妈的爱好,使用多重继承输出儿子喜欢做的事。

interface DadLikeDo{//定义“爸爸喜欢做的事”接口
    void smoke();//抽烟的方法
    void fish();//钓鱼的方法
}

interface MomLikeDo{
    void watchTV();//看电视的方法
    void cook();//做饭的方法
}

//继承DadLikeDo接口和MomLikeDo接口
public class SonLikeDo implements DadLikeDo,MomLikeDo {
    public void watchTV(){
        System.out.println("看电视");
    }

    public void cook(){
        System.out.println("做饭");
    }

    public void smoke(){
        System.out.println("抽烟");
    }

    public void fish(){
        System.out.println("钓鱼");
    }
    public static void main(String args[]){
        SonLikeDo son=new SonLikeDo();//通过子类创建接口对象
        System.out.println("儿子喜欢做的事情有:");
        //子类队形调用DadLikeDo和MomLikeDo两个接口被实现的所有方法
        son.watchTV();
        son.cook();
        son.smoke();
        son.fish();
    }
}

运行代码截图:
在这里插入图片描述

二、异常处理

1.什么是异常

概念:程序在运行过程中出现的不正常现象。如:数组越界、范围越界等不正常现象,当出现这些现象不处理时,程序将终止运行
异常处理的必要性:任何程序都可能存在大量的未知问题、错误;如果不对这些问题进行性正确处理,则可能导致程序的中断,造成不必要的损失
异常处理机制:Java编程语言使用异常处理机制为程序提供异常处理的能力。

2.异常的分类

Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。

  1. Error:JVM、硬件、执行逻辑错误,不能手动处理。(StackOverflowError&OutOfMemoryError)
  2. Exception:程序在运行和配置中产生的问题,可处理。(RuntimeException:运行时异常,可处理,可不处理&CheckedException:检查时异常,必须处理)

3.常见运行时异常

类型说明
NullPointerException空指针异常
ArrayIndexOutOfBoundsException数组越界异常
ClassCastException类型转换异常
NumberFormatException数字格式化异常
ArithmeticException算数异常

异常的产生:当程序在运行时遇到不符合规范的代码或结果时,会产生异常或程序员使用throw关键字手动抛出异常。
异常的传递:按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)并中断运行。

4.异常处理

Java的异常处理通过5个关键字来实现:

  1. try:执行可能产生异常的代码
  2. catch:捕获异常 ,并处理
  3. finally:无论是否发生异常,代码总能执行
  4. throw:手动抛出异常
  5. throws:声明方法可能要抛出的各种异常

1.try…catch

try{
    可能出现异常的代码
}catch(Exception e){
    异常处理的关键代码,如:getMessage()printStackTrace()
}

会出现三种情况:

  1. 正常请求
  2. 出现异常并处理
  3. 异常类型不匹配
    演示try…catch…语句的使用:输入两个数进行除法运算,注意当除数为零时需要抛出一个异常进行处理
import java.util.Scanner;

public class Demo1 {
    public static void main(String args[]){
        Scanner in=new Scanner(System.in);
        int result=0;//不能在try中声明这个result变量,因为如果在try中声明则该变量只能在try中使用,不能在try以外使用
        try {//将可能发生异常的代码放入try中
            System.out.println("请输入第一个数字:");
            int num1=in.nextInt();//输入的类型可能有问题
            System.out.println("请输入第二个数字:");
            int num2=in.nextInt();//输入的字符类型或输入零会出现问题
            result=num1/num2;
        }catch (Exception e){//捕获异常,是所有异常的父类
            //处理(异常处理后可以执行下面的程序)
            e.printStackTrace();//将出现的异常情况打印出来后执行下面的程序
        }
        System.out.println("运行结果是:"+result);
        System.out.println("程序结束了....");
    }
}

运行结果截图:
在这里插入图片描述注意:不活捕获到异常才执行了try…catch…外的两个输出语句。若没有异常处理或该异常处理失败则不会出现后面的两个输出语句。

2.try…catch…finally

try{
    可能出现异常的代码
}catch(Exception e){
    异常处理的相关代码,如:getMessage()printStackTrace()
}finally{
    是否发生异常都会执行,可以释放资源等...
}

(1)finally块是否发生异常都执行,可以释放资源
(2)finally块不执行的唯一情况,退出Java虚拟机
演示try…catch…finally…使用

import java.util.Scanner;

public class Demo1 {
    public static void main(String args[]){
        Scanner in=new Scanner(System.in);
        int result=0;//不能在try中声明这个result变量,因为如果在try中声明则该变量只能在try中使用,不能在try以外使用
        try {//将可能发生异常的代码放入try中
            System.out.println("请输入第一个数字:");
            int num1=in.nextInt();//输入的类型可能有问题
            System.out.println("请输入第二个数字:");
            int num2=in.nextInt();//输入的字符类型或输入零会出现问题
            result=num1/num2;
        }catch (Exception e){//捕获异常,是所有异常的父类
            //处理(异常处理后可以执行下面的程序)
            e.printStackTrace();//将出现的异常情况打印出来后执行下面的程序
        }finally {
            System.out.println("释放资源....");
        }
        System.out.println("运行结果是:"+result);
        System.out.println("程序结束了....");
    }
}

当没有异常时的运行结果截图:
在这里插入图片描述
有异常时的运行结果截图:
在这里插入图片描述

3.多重catch

try{
   可能出现异常的代码
}catch(异常类型1){
   满足异常类型1执行的相关代码
}catch(异常类型2){
   满足异常类型2执行的相关代码
}catch(异常类型3){
   满足异常类型3执行的相关代码
}

(1)子类异常在前,父类异常在后
(2)发生异常时按顺序逐个匹配
(3)执行第一个与异常类型匹配的catch语句
(4)finally根据需要可写或不写
演示多重catch语句

import java.util.InputMismatchException;
import java.util.Scanner;

public class Demo2 {
    public static void main(String args[]){
        Scanner in=new Scanner(System.in);
        int result=0;//不能在try中声明这个result变量,因为如果在try中声明则该变量只能在try中使用,不能在try以外使用
        try {//将可能发生异常的代码放入try中
            System.out.println("请输入第一个数字:");
            int num1=in.nextInt();//输入的类型可能有问题
            System.out.println("请输入第二个数字:");
            int num2=in.nextInt();//输入的字符类型或输入零会出现问题
            result=num1/num2;
        }catch (ArithmeticException e){//捕获异常,是所有异常的父类
            //处理(异常处理后可以执行下面的程序)
           System.out.println("算数异常");//将出现的异常情况打印出来后执行下面的程序
        }catch (InputMismatchException e){
            System.out.println("输入不匹配异常");
        }catch (Exception e){
            System.out.println("未知异常");
        }
        System.out.println("运行结果是:"+result);
        System.out.println("程序结束了....");
    }
}

输入不匹配异常运行结果截图:
在这里插入图片描述
算数异常运行结果:
在这里插入图片描述
多加几个catch可以使程序更加精确,且子类异常在前,父类异常在后

4.try…finally

  1. try…finally不能捕获异常,仅仅用来当发生异常时,用来释放资源。
  2. 一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。
try{
   可能出现异常的代码
}finally{
   是否发生异常都会执行,可以释放资源等...
}

演示try…finally…使用

import java.util.InputMismatchException;
import java.util.Scanner;

public class Demo3 {
    public static void main(String args[]){//JVM
        try {
            divide();
        }catch (Exception e){
            System.out.println("出现异常"+e.getMessage());
        }
    }
    public static void divide(){
        Scanner in=new Scanner(System.in);
        int result=0;//不能在try中声明这个result变量,因为如果在try中声明则该变量只能在try中使用,不能在try以外使用
        try {//将可能发生异常的代码放入try中
            System.out.println("请输入第一个数字:");
            int num1=in.nextInt();//输入的类型可能有问题
            System.out.println("请输入第二个数字:");
            int num2=in.nextInt();//输入的字符类型或输入零会出现问题
            result=num1/num2;
        }finally {
            System.out.println("释放资源");
        }
        System.out.println("运行结果是:"+result);
        System.out.println("程序结束了....");
    }
}

运行结果截图:
在这里插入图片描述
如果输入有异常发生不会出现finally外的输出结果

参考

【1】开源学习
【2】Java编程基础(第2版)清华大学出版社
【3】Java编程基础从入门到精通(小白速通篇)视频教程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值