面向对象(13-1):抽象类

面向对象(13):抽象类

1、抽象的表述

我们之前所说的猫,狗,猪,羊驼,熊猫等等都是动物的具体的例子,而动物本身是一个抽象的概念,
而我们之前是将动物写成了一个类,而类又可以创建对象,但是呢,实际上抽象的东西本身应该不能实例化,
并且动物这个概念中吃的方法,以及动物共有的方法本身也是一个不具体的方法,我们在今天之后,
把一个不具体的功能,叫做抽象方法,而如果说一个类中包含有抽象方法的时候,这个类叫做抽象类。

2、抽象类的特点

(1)抽象类和抽象方法 要用abstract关键字修饰

abstract修饰类:放在class前面
            举例:
                abstract class Animal3{}
abstract修饰方法:放在访问权限修饰符的后面
            举例:
                public abstract void eat();
                抽象方法没有方法体(没有大括号{}),直接以分号结尾

(2)有抽象方法的一定是抽象类,但抽象类中不一定有抽象方法(抽象类中只含有具体的成员方法也是可以的);
具体的类中不能有抽象方法,否则会直接报错

案例:
//动物本身是抽象的概念,不能写成具体的东西
//创建一个抽象类
abstract class Animal22{  //abstract修饰类的时候,abstract要放在class前面

    //动物的吃也是一个抽象的,不能写具体的怎么吃
    //创建一个动物吃的抽象方法
 public abstract void eat();//abstract修饰方法的时候,abstract放在访问权限修饰符的后面
                            //而且抽象方法没有方法体,大括号{}去掉
    //创建一个具体实现方法
    public void fun(){
        System.out.println("这是抽象类中的具体实现的fun方法");
    }
}
/*
	抽象类中,既可以包含抽象方法,也可以包含具体实现的方法(非抽象方法),不会报错
*/

错误案例:
    //创建一个具体的狗类
    class Dog {
        //单独在具体的类中创建抽象方法
        public abstract void show();//这样写 会报错
    }

(3)如果继承抽象类的是一个具体的类,要重写抽象类所有的抽象方法

错误案例:
//创建一个具体的狗类,继承抽象类Animal22
class Dog extends Animal22{	//这样写会直接报错
}

正确案例:上面如果想要不报错,要重写抽象类所有的抽象方法
/创建一个具体的狗类,Animal22
class Dog extends Animal22{
//继承抽象类的是一个具体的类,要重写抽象类所有的抽象方法
//重写抽象类中的抽象方法,快捷键 光标放在类名上,按住Alt+Enter,选择Implement methods回车
    @Override
    public void eat() {
        System.out.println("狗吃肉");//自己添加一个输出语句
    }


如果是一个抽象类继承抽象类,不需要重写抽象类中的方法

//创建一个抽象类Demo1,来继承抽象类Animal22
abstract class Demo1 extends Animal22{
    //抽象类继承抽象类,类中什么也不写,不会报错
}

(4)抽象类不能被实例化(就是说在测试类中,不能直接创建对象来调用抽象类中具体的方法)

既然不能被实例化,那写在抽象类中具体的方法怎么去调用呢?抽象类如果创建呢?

即:利用多态的形式,通过具体的子类实例化去调用方法

案例:想要调取抽象类中的fun方法

//动物本身是抽象的概念,不能写成具体的东西
//创建一个抽象类
abstract class Animal22{    //abstract修饰类的时候,abstract要放在class前面

    //动物的吃也是一个抽象的,不能写具体的怎么吃
    //创建一个抽象方法
    public abstract void eat();//abstract修饰方法的时候,abstract放在访问权限修饰符的后面
                                //而且抽象方法没有方法体,大括号{}去掉
    //创建一个具体实现方法
    public void fun(){
        System.out.println("这是抽象类中的具体实现的fun方法");
    }
}

//创建一个具体的狗类,继承抽象类
class Dog extends Animal22{
//继承抽象类的是一个具体的类,要重写抽象类所有的抽象方法
//重写抽象类中的抽象方法,快捷键 光标放在类名上,按住Alt+Enter,选择Implement methods回车
    @Override
    public void eat() {
        System.out.println("狗吃肉");//自己添加一个输出语句
    }
}

//测试类
public class AbstractDemo1 {
    public static void main(String[] args) {
    //抽象类中,不能直接创建抽象类对象,来调取抽象类中具体的方法
    //要利用多态的形式,通过具体的子类实例化去调用方法
    //使用抽象多态的形式创建对象(父类引用指向子类对象)
        Animal22 a = new Dog();
        a.fun();//可以调用抽象类中具体实现的fun方法
        a.eat();//可以调用具体狗类中的eat方法(该方法是重写抽象类的方法)
		//如果具体的类中有特有的方法,需要向下转型
    }
}

3、抽象类多态的案例

/*
    在抽象的动物类中定义两个抽象方法,吃饭和睡觉
    分析:
        1、创建一个抽象类:动物类
        2、定义吃饭和睡觉的抽象方法

        想要最终打印输出吃饭和睡觉,必须创建具体的类来继承抽象类,
        然后通过使用抽象类多态创建对象(父类引用指向子类对象)
        来调取具体的类中的方法
 */


//创建一个抽象类:动物类
abstract class Animal66{
    //定义吃饭和睡觉抽象方法
    public abstract void eat();
    public abstract void sleep();
}

//创建一个具体的类来继承抽象类
class Cat extends Animal66{
    //继承抽象类需要重写抽象类的所有抽象方法 快捷键 Alt+Enter回车
    @Override
    public void eat() {
        System.out.println("猫吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("猫睡觉");
    }
    //我们自己给猫添加一个特有的方法:抓老鼠
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

//测试类
public class AbstractDemo2 {
    public static void main(String[] args) {
        //使用抽象多态创建对象
        Animal66 a = new Cat();
        //调取具体类中的抽象方法
        a.eat();
        a.sleep();

        //如果想要调取具体类中特有的方法
        //则需要多态向下转型
        Cat c =(Cat)a;
        //向下转型后再调用特有的方法
        c.catchMouse();
    }
}

4、抽象类的成员特点

(1)抽象类中的成员变量:可以是变量,也可以是常量

abstract class Animal{
    public int a;
    public final int b = 20;
}

(2)抽象类中的构造方法:有构造方法,但是抽象类不能实例化

那构造的意义是什么呢?要想初始化子类,就必须先初始化父类,在继承的关系中有用

abstract class Animal{
    public int a;
    //手动创建构造方法
    Animal(){
        a = 20;
        System.out.println(a);
    }
}
//创建一个具体的类继承抽象 类
class Dog extends Animal{
}

//测试类
public class AbstractDemo{
    public static void main(String[] args) {
    	//创建Dog类的对象
        Dog d = new Dog();
    }
}
        执行结果是:
                20

                Process finished with exit code 0
                /*
                	在具体的类中并没有语句体,但是创建对象后仍可以输出20;
                	这说明要想初始化子类,就必须先初始化父类,在继承的关系中有用
                	所有执行的时候调用了抽象类的构造方法
                */

(3)抽象类中的成员方法

可以有抽象方法 限定子类必须完成某些动作;

也可以有非抽象方法 提高代码服用性

5、抽象类思考题

1、一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?

答:可以
意义:
橙汁,水,牛奶等这些东西用共同的特点,我们把这些相同的行为
概念归结成一个类;假设叫做液体。
至于后面有没有抽象方法,取决于这些东西有没有相同的行为,只是说有着相同的本质。没有
实际的共同的行为,也可不写抽象方法,也是合情合理的。
    (1)抽象类中可以没有抽象方法
    (2)抽象类不能被实例化

2、记住一句话:java中所有类都有一个共同的父类:Object

3、抽象类中可以存在哪些关键字?换句话说就是:abstract关键不能和哪些关键字共存?
此处的共存指的是不能在同一行!

abstract关键字可以和public关键字共存
public abstract void show();
abstract关键字和private关键字冲突
//private abstract void show1();
abstract关键字和final关键字冲突
//final abstract void show2();
abstract关键字和static关键字冲突
//static abstract void show3();
posted @ 2021-12-12 21:12  阿伟宝座  阅读(196)  评论(0)    收藏  举报