十八、OOP之理解《抽象类》

看完了面向对象的三大特性,接着我们进一步理解Java的抽象类接口
本篇介绍抽象类,下篇介绍接口

一、抽象类

抽象类 可以定义抽象方法, 同时 抽象方法必须存在于抽象类中
关键字:abstract 英文含义是"抽象的"
格式: abstract class 类名

1、抽象类的好处:
可以避免父类对某个方法进行实现,子类继承父类就必须重写抽象类中的抽象方法

抽象类不能创建对象: 抽象类用于被继承的类,可以定义抽象类的子类,由子类创建对象

2、抽象类的子类分类:

(1)子类重写了所有的抽象方法,子类就是一个普通类,可以创建对象

(2) 如果没有完全重写,此时还是一个抽象类,必须使用abstract关键字修饰,子类还是无法创建对象

抽象方法 例如 public abstract void eat();

abstract 修饰 有继承关系 需要被子类重写方法

  • 只有方法的声明,没有方法的实现,没有大括号,在参数列表后直接加上分号

3、抽象类的特点

抽象类和抽象方法都需要使用abstract关键字

(1) 抽象方法:public abstract 返回值类型 方法名称(参数列表);

(2) 抽象类:abstract class 类名

4、抽象类方法的关系

(1) 抽象方法必须存在于抽象类中

(2) 抽象类中可以没有抽象方法

public class Demo01 {
}
//抽象方法必须存在于抽象类中
abstract class Pet{
    public abstract void eat();
}
//被继承的Pet类中有抽象方法,抽象类的抽象方法,会强制要求子类一定要重写
class Dog extends Pet {
    //父类中的抽象方法,子类必须进行重写,否则编译报错
    @Override
    public void eat() {
        System.out.println("吃骨头");
    }
}
class Cat extends  Pet {
    @Override
    public void eat() {
        System.out.println("吃猫粮");
    }
}
class Monkey extends  Pet {
    @Override
    public void eat() {
        System.out.println("吃香蕉");
    }
}
public class Demo02 {
    public static void main(String[] args) {
//        Fu f = new Fu();抽象类不能创建对象

        Zi z = new Zi();
        z.test1();
        z.test2();
        z.test3();
//        Zi2 z2 = new Zi2();
    }
}
abstract class Fu{//有抽象方法的类,一定是抽象类
    public abstract void test1();
    public abstract void test2();
    //抽象类中不一定有抽象方法
    public void test3(){
        System.out.println("今天是周一,愉快的黑色星期一");
    }
}
class Zi extends Fu{
    //将光标放在报错的位置,alt+enter会提示解决问题的方式,选择即可
    @Override
    public void test1() {
        System.out.println("实现了抽象方法test1");
    }
    @Override
    public void test2() {
        System.out.println("实现了抽象方法test2");
    }
}
//如果一个抽象类中的抽象方法,子类没有完全实现,那么这个类还是一个抽象类,不能创建对象
abstract class Zi2 extends Fu{
    @Override
    public void test1() {
        System.out.println("~~~~~~~~~~~");
    }
}

3、注意事项

1、抽象类可以定义成员变量

(1) 抽象类可以定义成员变量,也可以定义常量,由于抽象类不能实例化,所以定义的属性不能被抽象类使用,但是能够被抽象类的子类去使用

2、抽象类能不能有构造方法

(1) 可以有构造方法,虽然不能创建对象,但是抽象类一般都会有子类,子类会访问父类的构造方法,来完成对父类的成员变量的初始化赋值

(2) 能否定义构造方法,不是取决于该类能否创建对象,关键在于能否定义成员变量,一个类能定义成员变量,那么就可以有构造方法

3、抽象类也可以有成员方法

(1) 抽象类也可以有成员方法,这里定义的方法,子类一般不会去重写

(2) 抽象方法的目的就是为了让子类重写

4、抽象类:一般适合用于定义事物先天具有的属性和行为,先天具备

public class Demo03 {
    public static void main(String[] args) {
        Person.say();
        Student s = new Student("陈毅1");
        System.out.println(s.name);
        s.name = "陈毅";
        System.out.println(s.name);
    }
}
//人类作为只能用于被继承的类
abstract class Person{
    //定义成员变量
    int a = 20;
    String name;
    //定义常量
    final int VERSION = 1;//final表示最终的不可修改的

    //有成员变量,就初始化 默认显式构造
    public Person(){}
    public Person(String name){
        this.name = name;
    }
    //抽象方法
    public abstract void sleep();
    //普通方法
    public void eat(){
        System.out.println("~~~~~~~~~~~干饭时间又快到了");
    }
    //抽象类中可以有静态方法,直接通过类名访问
    public static void say(){
        System.out.println("~~~~~~~~~~~~~");
    }
}
class Student extends Person{
    //此时默认会有一个空参
    public Student(){
        super();
    }
    //可以提供一个有参构造
    public Student(String name){
        super(name);
    }
    @Override
    public void sleep() {
        System.out.println("一起睡觉");
    }
}

练习

1、定义宠物类:属性 姓名 性别 年龄 行为 吃 喝 睡

2、定义狗: 属性 姓名 性别 年龄 行为 吃 喝 睡 咬你的好朋友(他叫陈毅)

3、定义猫: 属性 姓名 性别 年龄 行为 吃 喝 睡 抓你的好朋友(他也叫陈毅)

package com.ujiuye.test;

public class Demo01 {
    public static void main(String[] args) {
        Cat c = new Cat("小黑","母",11);
        c.catchC();
        System.out.println(c.getName());
        c.drink();
        c.eat();
    }
}
//1、定义宠物类:属性 姓名 性别 年龄  行为 吃 喝 睡
//        2、定义狗: 属性 姓名 性别 年龄  行为  吃 喝 睡 咬陈毅
//        3、定义猫: 属性 姓名 性别 年龄  行为  吃 喝 睡 抓陈毅
abstract class Pet{
    private String name;
    private String sex;
    private int age;

    public Pet() {
    }
    public Pet(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public abstract void eat();
    public abstract void drink();
    public void sleep(){
        System.out.println("闭眼睛睡觉");
    }
}
class Dog extends Pet{
    public Dog() {
    }
    public Dog(String name, String sex, int age) {
        super(name, sex, age);
    }
    @Override
    public void eat() {
        System.out.println("吃陈毅");
    }
    @Override
    public void drink() {
        System.out.println("喝水");
    }
    public void bite(){
        System.out.println("咬陈毅");
    }
}
class Cat extends Pet{
    public Cat() {
    }
    public Cat(String name, String sex, int age) {
        super(name, sex, age);
    }
    @Override
    public void eat() {
        System.out.println("吃猫粮");
    }
    @Override
    public void drink() {
        System.out.println("喝牛奶");
    }
    public void catchC(){
        System.out.println("抓陈毅");
    }
}

扩展: 模板设计模式

1、设计模式:是一种反复使用,多人知晓,经过分析编辑代码、代码设计经验的总结

2、使用设计模式的目的: 为了让代码更容易被别人理解,保证代码的可靠性和程序的重用性

3、模板设计模式:把抽象类整体看做一个模板,不能决定的内容 使用抽象方法表示,让使用模板的类【抽象类的子类】去重写抽象方法实现需求

4、好处:优势在于设定好通用的结构,使用者只需要直接拿着去用就可以,只需要关注自己实现的内容即可

public class Demo02 {
    public static void main(String[] args) {
        Mark m = new Mark();
        m.write();
    }
}
//作文模板类
abstract class Template{
    //书写作文的方法
    public void write(){
        //书写作文的标题
        System.out.println("陈毅和他的女朋友去放风筝");
        //作文的正文
        body();
        //作文的结尾
        System.out.println("放风筝可是真开心啊!!!");
    }
    //把作文的内容提取到一个方法中,方法如果有方法体正文就写死了,所以写成一个抽象方法
    public abstract void body();
}
//模板使用者
class Mark extends Template{
    @Override
    public void body() {
        System.out.println("今天风和日丽,陈毅和他的女朋友去公园放风筝,但是没有风筝,后来就陈毅就把他女朋友绑在线上放飞了");
    }
}

补充:

1、多态关系的构建语法格式是? 父类的引用指向子类对象
2、多态的前提是? 先构建继承关系,没有继承就没有多态
3、多态访问成员方法的特点   编译看左运行看右
4、多态访问成员变量的特点   编译看左运行看左
5、多态的好处是什么	提高了代码的扩展性
6、什么是向上转型,什么是向下转型
多态的体现就是向上转型,父类的引用指向子类对象
恢复子类本身的访问范围,类型强制转换  子类类型  新对象名 = (子类类型)对象名;
7、抽象方法如何定义
	public abstract 返回值类型 方法名称(参数列表);
8、抽象类和抽象方法有什么关系
	抽象类中不一定有抽象方法,
         抽象方法必须在抽象类中
9、抽象类和普通类有什么区别
	多了抽象方法
	不能创建对象
	子类必须重写抽象类中的抽象方法
10、抽象类可以创建对象吗  
       不能
11、抽象类的子类一定能够创建对象吗
	不一定
	子类如果重写了所有的抽象方法  可以创建
	如果没有全部重写父类的抽象方法,还是一个抽象类
12. 定义一个Man, 属性有姓名, 方法: 开车
   有一个公交车类Bus, 属性有:速度 方法有: 跑
   有一个卡车类Truck, 属性有:速度 方法有: 跑
   有一个跑车类SportsCar:  属性有:速度 方法有: 跑
   要求:编写一个测试类: 创建一个Man对象,可以驾驭上面任意一款车型
        Man m = new Man();
public class Demo01 {
    public static void main(String[] args){
        Man m = new Man();
        m.name = "陈毅";
        m.driverCar(new Bus(100));
        m.driverCar(new SportsCar(30));
        m.driverCar(new Truck(120));
    }
}
//12. 定义一个Man类, 属性有姓名, 方法: 开车
//        有一个公交车类Bus, 属性有:速度 方法有: 跑
//        有一个卡车类Truck, 属性有:速度 方法有: 跑
//        有一个跑车类SportsCar:  属性有:速度 方法有: 跑
//        要求:编写一个测试类: 创建一个Man对象,可以驾驭上面任意一款车型
class Man{
    String name;
    public void driverCar(Car c){
        c.run();
    }
}
abstract class Car{
   private int speed;
    public int getSpeed() {
        return speed;
    }
    public void setSpeed(int speed) {
        this.speed = speed;
    }
    public Car(int speed) {
        this.speed = speed;
    }
    public abstract void run();
}
class Bus extends Car{
    public Bus(int speed) {
        super(speed);
    }
    @Override
    public void run() {
        System.out.println("摇摇晃晃" +getSpeed());
    }
}
class Truck extends Car{
    public Truck(int speed) {
        super(speed);
    }
    @Override
    public void run() {
        System.out.println("横推一切" + getSpeed());
    }
}
class SportsCar extends Car{
    public SportsCar(int speed) {
        super(speed);
    }
    @Override
    public void run() {
        System.out.println("风驰电掣" + getSpeed());
    }
}
13.编一个Perosn, 包含属性姓名, 年龄, 行为:说话, 吃饭, 睡觉
  Person有一个子类Student,Person多一个属性分数, 重写说话, 吃饭,睡觉的方法
  Person有一个子类Teacher,Person多一个属性薪资, 重写说话, 吃饭,睡觉的方法
	人类下每个子类对行为的实现均不相同
 编写测试类StudentTeacher对象,并调用每个对象的方法.
public class Demo02 {
}
//13.编一个Perosn, 包含属性姓名, 年龄, 行为:说话, 吃饭, 睡觉
//        Person有一个子类Student, 比Person多一个属性分数, 重写说话, 吃饭,睡觉的方法
//        Person有一个子类Teacher, 比Person多一个属性薪资, 重写说话, 吃饭,睡觉的方法
//        人类下每个子类对行为的实现均不相同
//        编写测试类Student和Teacher对象,并调用每个对象的方法.
//
abstract class Person{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public abstract void say();
    public abstract void eat();
    public abstract void sleep();
}
class Student extends Person{
    private int score;
    public Student() {
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
    public Student(String name, int age, int score) {
        super(name, age);
        this.score = score;
    }
    @Override
    public void say() {
        System.out.println("谈天说地就是不聊学习");
    }
    @Override
    public void eat() {
        System.out.println("干饭人,干饭魂。吃最重要");
    }
    @Override
    public void sleep() {
        System.out.println("教室里睡的最香");
    }
}
class Teacher extends Person{
    private int salary;
    public Teacher() {
    }
    public Teacher(String name, int age, int salary) {
        super(name, age);
        this.salary = salary;
    }
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
    @Override
    public void say() {
        System.out.println("那叫一个说啊,一直说,一说六个小时");
    }
    @Override
    public void eat() {
        System.out.println("吃,也是最重要的,同是干饭人");
    }
    @Override
    public void sleep() {
        System.out.println("上班天天打瞌睡 不能睡");
    }
}
14. 有如下代码,请问哪些是不正确的?(    )
       class ClassA{}
        class ClassB extends ClassA{}
        class ClassC extends ClassA{}
        //BC是A的子类
        ClassA p0 = new ClassA();//A类引用指向A类对象
        ClassB p1 = new ClassB();//B类引用指向B类对象
        ClassC p2 = new ClassC();//C类引用指向C类对象
        ClassA p3 = new ClassB();//A类的引用指向B类的对象
        ClassA p4 = new ClassC();//A类的引用指向C类的对象
//        A类的引用 = B类的对象
        p0 = p1;  //合理
        //sp1 = p2;//b类的引用 = C类的对象  BC都是子类 没有直接关系  所以不可以
        //必须是父类的引用指向子类对象才可以
        p1 = (ClassB)p3;//B类的引用  向下转型 将P3转为B类的引用B类的对象
        p2 = (ClassC)p4;//同上
  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值