0
点赞
收藏
分享

微信扫一扫

JavaSE基础(十)---抽象类和接口

90哦吼 2022-05-01 阅读 213

目录

一、抽象类

1、抽象类的概念

2、抽象类的语法

3、抽象类的注意事项

4、抽象类的作用

二、接口 

1、接口的概念        

2、接口的语法

3、接口的使用

4、接口的特性

5、实现多个接口

6、接口之间的继承

三、接口的使用实例

1、Comparable接口

 2、Comparator接口(比较器)


一、抽象类

1、抽象类的概念

在面向对象的过程中,通过类的描述来实例化对象,但是有时会出现一些类,这些类没有足够的信息具体地描述某一个对象。这样的类就被称为“抽象类”。


比如,在一个分析图形的过程中,图形类中存在着圆、三角形、正方形等图形,这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域并不是直接存在的,它就是一个抽象概念。

图形Shape和圆、三角形、正方形之间存在继承关系。

图形Shape类不是具体的图形,所以即使其内部存在draw()方法,也没办法实现该方法。

如果我们对这些图形都进行draw()绘画的动作,那么根据对象的不同,所绘制出来的也是不一样的,可图形类(Shape)作为父类,没法具体绘画出具体的图形,导致draw()方法无法具体地实现因此把图形类(Shape)称为“抽象类”。

        在打印图形例子中, 父类 Shape 中的 draw()方法并没有什么实际工作, 主要的绘制图形都是由 Shape 的各种子类(三角形、圆形、正方形)的 draw()方法来完成的.

        像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstract method), 包含抽象方法的类我们称为 抽象类(abstract class).

打印图形示例:

abstract class Shape{
    abstract public void draw();
}
class Circle extends Shape{
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}
class triangle extends Shape{

    @Override
    public void draw() {
        System.out.println("▲");
    }
}
class square extends Shape{

    @Override
    public void draw() {
        System.out.println("□");
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
        //注意:不能实例化抽象类,此处实例化继承抽象类的子类
        Shape shape=new Circle();
        Shape shape1=new triangle();
        Shape shape2=new square();
        shape.draw();
        shape1.draw();
        shape2.draw();
    }
}

2、抽象类的语法

一般情况下,我们把被抽象化的类称为“抽象类”,而在抽象类中被抽象化的方法被称为“抽象方法”。抽象方法不需要有具体的实现语句.

而抽象类和抽象方法都是由abstract修饰的。

【注意】:

  • 当一个方法的具体实现不想写,加个abstract就可以让它抽象化,类也要加上abstract,让其变成抽象类。 
  • 类中多了一个抽象方法,这个类也得变成抽象类。
  • 抽象类和普通类的差不多,内部也可以具有普通成员变量、普通方法和构造方法。
  • 抽象类中可以没有抽象方法,但如果一个类中有抽象方法,那该类一定得是抽象类。

3、抽象类的注意事项

 在Java中,抽象类的使用有许多要注意的地方。稍不注意,就容易导致程序运行时报错,或出现意想不到的错误结果。


4、抽象类的作用

 一般情况下,我们都是用普通的父类和子类进行向上转型,之后再通过调用它们之间重写的方法,发生动态绑定,来具体实现某一个对象的功能。

但还是建议重写抽象类中的抽象方法。

而抽象类本身是不能被实例化的,要想使用,只能先创建一个继承该抽象类的子类,然后让该子类重写抽象类的抽象方法。


二、接口 

1、接口的概念        

对于接口,在日常生活中,我们首先可以联想到的:我们平常充电USB口,电源插头等等。

根据接口的不同,可以插不同的设备。

比如:电脑的USB口上,可以插:U盘、鼠标、键盘...所有符合USB协议的设备

           电源插座插孔上,可以插:电脑、电视机、电饭煲...所有符合规范的设备


2、接口的语法

接口其实和类差不多,但还是有所差别。接口的定义格式和类的定义格式基本相同。

接口是用interface关键字修饰的。

将平时定义类的class关键字,更换成interface关键词,就定义了一个接口。

接口的定义示例:

【注意】:

接口的语法规则:

  • 接口是由interface关键字修饰的。
  • 接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一形式进行定义。
  • 接口中的方法都是抽象方法,默认为public abstract。
  • 接口中存在成员变量,但都默认为public static final静态常量,都得进行初始化。
  • 创建接口时,接口的命名一般都是以大写字母I开头。
  • 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.

3、接口的使用

接口不能直接使用,需要有一个类来实现该接口,而该类还需重写接口中所有的抽象方法。

换句话说,一个类如果遵循了特定接口的规范,那么该类需要履行接口中的功能服务。

而将类声明为实现某一接口,需要用implements关键字。

语法格式:

class 类名词 implements 接口名称{
    ...
}

 【注意】:子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系


接口使用的代码示例:

以Animal接口,Dog类和Cat类实现该接口为例子


4、接口的特性

接口具有必须注意的特性。

(1)接口虽然是一种引用数据类型,但是不可以实例化new接口的对象,需要通过类实现该接口,之后实例化这个类对象。

 

(2)接口内的成员变量默认为静态常量,必须初始化,接口当中的成员变量即使不写public static final也会默认是public static final!

(3)接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的默认为 public abstract,即使没有修饰符,编译器也会自动默认为public abstract(而且只能是 public abstract,其他修饰符都会报错) 

(4)接口中的方法是不能在接口中实现的,但可以定义静态方法来实现该方法。

 

(5) 在继承抽象类或实现接口时所有不想重写抽象方法的类,都可以使它变成抽象类 

 

(6) 重写接口中方法时,不能使用default访问权限修饰

 

 (7)接口当中的方法如果要实现,需要用default来修饰。(这个默认的方法可以被重写)

 

(8)接口中不能有静态代码块和构造方法

 

(9)接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

以此处代码为例

 


5、实现多个接口

接口不像类的继承一样(在Java中,类和类之间是单继承的),子类在继承父类的时候,一次只能继承一个父类,没法继承多个。(Java中不支持多继承)

而类实现接口,可以同时实现多个。

实现的多个接口之间是通过逗号分隔开的。

 


对于我们前面学习到的继承关系,子类继承父类的这种关系,比如Animal和Dog类之间表达的是一种is-a 关系(狗是动物)。

而在实现接口这个地方,表达的含义是该Dog类具有Swim,Move等特性.

狗是一种动物,具有跑,游泳的特性。


6、接口之间的继承

在Java中,类和类之间是单继承的,一个类可以实现多个接口,

而接口与接口之间可以多继承。

即:用接口可以达到多继承的目的。 接口可以继承一个接口, 达到复用的效果. 和类继承一样使用 extends 关键字.

也就是说,一个接口继承其他接口,就具备了其他接口的功能。

比如:


三、接口的使用实例

1、Comparable接口

使用类来实现接口,可以帮助我们很方便地进行许多有意思地操作。

(具体内部源码暂不作分析)

 (1)首先我们先定义一个学生类

 (2)定义一个Student学生类数组,里面存放实例化的学生对象.

 (3)如果要对学生对象进行比较,我们得先确定要比较的属性是什么,类和普通的整型是不一样,整型是可以直接比较的, 大小关系明确,可不能说直接用学生的引用变量进行比较。

 (4)比如,以学生的年龄作为比较条件,我们可以让Student学生类,实现一个Comparable的接口,该接口是Java中自带的。

 

 需要注意的是,在Comparable接口后面有一个尖括号,里面应该存放要比较的类类型。

之后要在该Student类中重写ComparTo()方法

 如果没有重写该方法,会报编译错误。

 (5)如果我们想比较的是学生的年龄,那么我们可以在compareTo()方法中,返回比较的两个学生对象年龄之差。(如果比较的是成绩,把age替换成score即可)

如果返回的是正数,说明前者的学生年龄大;

如果返回的是负数,说明后者的学生年龄大;

如果返回的是0,说明两者的年龄一样大。

(6)在前面我们定义了一个学生类数组,我们可能通过Arrays类调用内部的sort()排序来对学生类进行排序。 

在 sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.

之后我们再通过Arrays.toString ()方法将该数组转换为字符串输出,即可输出学生对象之间的年龄大小关系.

 【注意】:使用Arrays时,记得要导包.

(7)如果比较的是学生对象的名字(字符串)该怎么比较呢?

只需再调用一个compareTo()方法比较, (具体内部源码暂不作分析) 


 2、Comparator接口(比较器)

下面引出Comparator(比较器)

通过实现Comparator接口,我们后续可以很方便地对类对象进行各种比较。  


 如果我们想比较学生的成绩,我们可以定义一个实现Comparator接口的成绩比较类ScoreIgnore.

Comparator接口和Comparable接口一样,后面的尖括号内为要比较的类类型。

通过重写compare方法,来返回比较的结果

 

之后再通过实例化ScoreIgnore对象,通过Arrays中的sort方法,传入该对象和要比较的学生数组students,进行比较。Arrays类中的sort()方法会进行一系列相关操作. 


如果要比较学生对象的名字大小,可以在重写的compare方法内,再调用compareTo方法进行比较.

 

举报

相关推荐

0 条评论