Java面向对象——抽象方法和抽象类

Java面向对象——抽象方法和抽象类

1.引出抽象方法设计

我们知道,图形都有对应算法来求出面积,如下方代码所示,我们创建Graph.java代表图形类,图形类中提供计算面积的getArea()方法,因为每种具体图形的面积计算公式都不一样,所以我们让Graph类中的getArea()方法只提供一个返回值,由子类进行覆盖。创建圆形类、矩形类代表不同的图形,它们都继承自图形类,并各自覆盖getArea()方法。

/**
* 图形类
*/
public class Graph {

   public Double getArea(){
       return 0.0;
   }
}
/**
 * 圆类 继承自 图形类Graph
 */
public class Circle extends Graph{

    private Double r;

    /**
     * 提供有参构造
     * @param r 圆的半径
     */
    public Circle(Double r){
        this.r = r;
    }

    /**
     * 计算圆形面积
     * @return
     */
    @Override
    public Double getArea() {
        return 3.14 * r * r;
    }
}
/**
 * 矩形 继承自 图形类Graph
 */
public class Rectangle extends Graph{

    /**
     * 长方形的长
     */
    private Double length;

    /**
     * 长方形的宽
     */
    private Double width;

    public Rectangle(Double length, Double width){
        this.length = length;
        this.width = width;
    }

    /**
     * 计算矩形面积
     * @return
     */
    @Override
    public Double getArea() {
        return length * width;
    }
}

我们分析以上代码,会发现存在两个问题:

  • 1.每一种图形都有面积,所以在Graph类中定义求面积的方法getArea()没问题。但是,不同的具体图形求面积的算法是不一样的,也就是说,每一种图形的子类都必须去覆盖getArea()方法,如果不覆盖,应该在语法上给出提示(报错) 。比如说我们新创建一个三角形类也继承自Graph类,没有覆盖getArea()方法,此时求三角形面积会调用父类的getArea()方法,返回值为0.0,肯定是不对的,因为三角形是有具体的不同于其他图形的求面积的公式。

  • 2.在图形类中定义了getArea方法,该方法不应该存在方法体,因为不同图形子类求面积算法不一样,父类真不知道该怎么写,所以应该提供无方法体

解决上述问题,我们可以将Graph类中的getArea()方法定义为抽象方法.

2.抽象方法

我们先看一下抽象方法的概念和格式:

抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就是没有方法体。

具体格式如下:
访问权限 abstract 返回值类型 方法名(形参列表);
public abstract void getArea();

按照上述格式,我们将Graph类进行相应的改造:

/**
 * 图形类
 */
public abstract class Graph {
    /**
     * 抽象方法
     * @return
     */
    public abstract Double getArea();
}

可以看到,Graph类也被abstract修饰,是因为Java中有明确要求,一旦类中包含了abstract方法,那类该类必须声明为abstract类。 如果Graph类不用abstract修饰,IDEA或者java文件编译时会有相应报错提示,阻止程序运行:
Class ‘Graph’ must either be declared abstract or implement abstract method ‘getArea()’ in ‘Graph’
在这里插入图片描述

因为之前的Circle类和Rectangle类都已经覆盖了getArea()方法,我们不需要再有相应改动.新创建一个三角形类Triangle.java,让其继承自Graph类,如果Triangle类不覆盖getArea()方法,IDEA中或者java文件编译时会有相应报错提示,阻止程序运行:
Class ‘Triangle’ must either be declared abstract or implement abstract method ‘getArea()’ in ‘Graph’
在这里插入图片描述

必须要强制覆盖父类的抽象方法

public class Triangle extends Graph{
    private Integer a;
    private Integer b;
    private Integer c;
    Triangle(Integer a, Integer b, Integer c)
    {
        this.a = a ;
        this.b = b;
        this.c = c;
    }

    /**
     * 根据海伦公式求三角形面积
     * @return
     */
    @Override
    public Double getArea()
    {
        Double p = (a + b + c)/2.0;
        return Math.sqrt(p *(p - a ) * (p - b ) * (p - c ));
    }
}

我们在之前提到的两个问题都得到了解决. 我们进行下总结:

使用 abstract 修饰且没有方法体的方法,称为抽象方法.

特点:

  • 1 使用抽象abstract修饰,方法没有方法体,留给子类去实现/覆盖.
  • 2 抽象方法的修饰符不能是private和final以及static,因为被这些修饰符修饰,子类无法对抽象方法进行覆盖.
  • 3 抽象方法必须定义在抽象类或接口中 (接口中定义的方法都是公共的抽象方法,默认使用public abstract来修饰方法,但一般的,我们在接口中定义方法,不喜欢使用修饰符).

3.抽象类

被abstract关键字修饰后,Graph类变为抽象类,所以说:

抽象类主要指不能具体实例化的类并且使用abstract关键字修饰。

通过上述例子我们知道父类Graph类只是定义了getArea()方法,具体的功能还得子类来实现,抽象类必须有子类才有意义,才能完成自己未尽的功能

需要注意的是,抽象类不能创建实例,即使创建出抽象类对象,调用抽象方法,根本没有方法体,没有任何意义!

对于抽象类来讲,普通类有的成员(方法、字段、构造方法),抽象类都有。 抽象类的构造方法不能全都定义为私有的(private修饰),否则不能有子类(创建子类对象前先调用父类构造方法)。

/**
 * 图形类
 */
public abstract class Graph {

    /**
     * 抽象类的成员变量
     */
    public String name;
    
    /**
     * 抽象方法
     * @return
     */
    public abstract Double getArea();

    /**
     * 抽象类的普通方法(非抽象方法)
     */
    public void print(){
        System.out.println("抽象类也可以具备普通方法-----");
    }

    /**
     * 抽象类的构造方法
     */
    public Graph() {
    }
}

总结下抽象类的特点:

  • 1.不能创建实例即不能new一个抽象类对象,即使创建出抽象类对象,调用抽象方法,根本没有方法体。

  • 2.可以不包含抽象方法,若一旦包含,该类必须作为抽象类,抽象类可以包含普通方法(留给子类调用的,抽象类是有构造器的子类构造器必须先调用父类构造器。

  • 3.若子类没有实现/覆盖父类所有的抽象方法,那么子类也得作为抽象类(抽象派生类)。

  • 4.构造方法不能都定义成私有的,否则不能有子类(创建子类对象前先调用父类构造方法)。

  • 5.抽象类不能使用final修饰,因为必须有子类,抽象方法才能得以实现。

  • 6.是不完整的类,需作为父类(必须要有子类),功能才能得以实现。

抽象类中可以不存在抽象方法如此这样没有太大的意义,但是可以防止外界创建对象,所以我们会发现有些工具类没有抽象方法但是也使用abstract来修饰。

抽象类和普通类对比:

  • 普通类有的成员(方法字段,构造器),抽象类都有。
  • 抽象类不能创建对象,抽象类中可以包含抽象方法。

4.抽象类的实际意义

• 抽象类的实际意义不在于创建对象而在于被继承。
• 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式。

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象的编程中,C语言并不直接支持类和抽象的概念。引用中提到,final关键字用来修饰方法,表示该方法不能在子类中被覆盖。而abstract关键字用来修饰抽象方法,表示该方法必须在子类中被实现。然而,在C语言中,没有对应的关键字来实现类和抽象的概念。 相反,C语言通过结构体来模拟类的概念。结构体是一种用户自定义的数据类型,可以包含多个不同类型的数据成员。通过结构体,我们可以将相关的数据和功能组合在一起。然而,C语言中的结构体不支持继承和多态等面向对象的特性。 在C语言中,我们可以使用函数指针来模拟抽象类和接口的概念。函数指针可以指向不同的函数,通过使用函数指针,我们可以实现多态性,即在运行时根据函数指针指向的具体函数来执行不同的操作。 综上所述,C语言并不直接支持面向对象中的类和抽象的概念,但可以使用结构体和函数指针来实现类似的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [面向对象——类和对象](https://blog.csdn.net/shouyeren_st/article/details/126210622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [面向对象编程原则(06)——依赖倒转原则](https://blog.csdn.net/lfdfhl/article/details/126673771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值