Java中的类,抽象类和接口

想必大家对Java中的实体类都比较熟悉。实体类通过属性和方法去描述一系列相似对象的特征。例如我们要写一个程序去计算图形的面积,需要定义一个长方形的类:

public class Rect {

    private double width;
    private double height;

    public Rect(double width, double height, String color) {
        this.width = width;
        this.height = height;
        this.color = color;
    }

    public double area() {
        return width * height;
    }
}

Rect类中有着实例字段去描述长方形的宽高以及图形的颜色,area()方法用来计算长方形的面积。我们再定义一个圆形的类:

public class Circle {
    
    private double radius;
    private String color;

    public Circle(double radius, String color) {
        this.radius = radius;
        this.color = color;
    }
    
    public void area() {
        return Math.PI * radius * radius
    }
} 

我们可以发现,Rect类和Circle类有一部分代码是相似的,例如color字段和area()方法。然而,由于计算面积的公式不同,area()的具体实现在这两个类中是不同的。这时,我们就可以创建一个新的类将相似的代码抽象出来。

public abstract class Shape {

    private String color;

    public Shape(String color) {
        this.color = color;
    }

    public abstract double area();
}

可以看到Shape类和Rect类以及Circle类的一个明显不同是,class前面多了一个abstract修饰符,这代表着Shape是一个抽象类而非实体类。抽象类和实体类的一个明显的区别就是,抽象类中包含有抽象方法(没有具体实现的方法)。换句话说,包含有抽象方法的类被称为抽象类。在Shape类中,area()就是一个抽象方法。它比普通方法多了一个abstract修饰符,并且没有由花括号包裹起来的方法体。

抽象类不能被实例化,但可以被继承。抽象类的子类必须实现父类的抽象方法(重写并使其有着具体的实现),否则子类也应该被定义为抽象类(继承了父类的抽象方法而未实现)。在这个例子中,Shape类的子类必须实现area()方法。

可能有人会问,抽象方法的存在只是为了简化代码吗?其实并不是的。抽象方法实际上定义了子类必须实现的“规范”。上层代码只定义规范,具体的业务逻辑由不同的子类实现,调用者并不关心子类的具体实现。同时,由于抽象方法的存在,在编写代码的时候不需要子类就可以实现业务逻辑(正常编译不报错)。例如我们只有一个抽象类Shape,要写一个ShapeUtil类,里面有计算图形面积之和的方法。

public class ShapeUtil {

    public double sum(Shape[] shapes) {
        double s = 0;
        for (Shape shape : shapes) {
            s += shape.area();
        }
        return s;
    }
}

可以看到,在计算面积和时,我们并不关心每一个图形的面积是如何计算的,我们只负责处理面积求和的业务逻辑,而把计算每个图形面积的具体实现交给了子类处理。也就是说,抽象方法定义了规范(area()方法需要返回图形的面积),而具体的实现交给了子类。

接下来我们使用抽象类来实现Rect类和Circle类:

public class Rect extends Shape {

    private double width;
    private double height;

    public Rect(double width, double height, String color) {
        super(color);
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return width * height;
    }
}
public class Circle extends Shape{

    private double radius;

    public Circle(double radius, String color) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

可以看出,除了拥有抽象方法外,抽象类和普通类一样,同样可以拥有成员变量和普通的成员方法。抽象类和普通类在用法上也是相似的,在继承抽象类时使用extends关键字,一个类只能继承一个抽象类

如果一个抽象类没有字段,所有方法全部是抽象方法,就可以把该抽象类改写为接口。接口是一种声明的集合,是一种声明的规范,里面包含了很多抽象方法。需要明确的一点是,接口不是类,类描述对象的属性和方法,接口则包含类要实现的方法。

接口用interface来声明,它无法实例化。它可以被类实现(implements),无法被继承。当接口被类实现时,除非该类为抽象类,否则该类需要实现接口中所规定的所有抽象方法。我们将以上代码改写,使用interface来实现:

public interface Shape {

    double area();
    
}

public class Rect implements Shape {

    private double width;
    private double height;

    public Rect(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return width * height;
    }
}
public class Circle implements Shape {

    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

接口和抽象类是有相似之处的。接口可以继承自另一个接口(使用extends关键字),相当于扩展类接口的方法。接口定义的方法默认是public abstract(不需要写)。接口与抽象类的一些区别如下:

抽象类 接口
继承 一个子类只能继承一个抽象类 一个子类可以实现多个接口
成员变量类型 各种类型均可 只能是 public static final
抽象方法 可以定义抽象方法 可以定义抽象方法
非抽象方法 可以定义非抽象方法 可以定义default方法*
static方法 可以有static方法/代码块 不能含有static修饰的方法

*:default方法是一个非抽象方法,所有实现接口的类都不需要实现这个方法,任何子类都可以重写这个方法来实现它自己的逻辑。

接口的作用主要是作为一个上层的规范。比如我们要开发一个无人驾驶汽车的软件。开发过程中,我们需要GPS服务提供商提供GPS相关的服务(例如,定位、导航),我们还需要汽车制造厂商提供操控汽车的服务(例如,加速、刹车、转弯等)。这两种服务是不相关的,GPS公司和汽车厂商不需要了解对方公司是如何提供服务的(具体的代码实现)。在这种情况下,我们可以使用接口。我们写出GPS服务的接口和汽车操控的接口,根据接口来处理业务逻辑。与此同时,GPS提供商和汽车厂商可以根据我们提供的接口规范去实现具体功能。

如何判断该使用抽象类还是接口呢?

当以下情况适用于你时,可以考虑使用抽象类:

  • 你希望在一些紧密相关的类中共享代码
  • 你需要被继承的类拥有一些共同的方法、字段,或者需要除了public以外的访问修饰符(例如protected/private)
  • 你希望声明一些非静态/非常量的字段(你可以定义一些方法去获取/修改对象的属性)

当以下情况适用于你时,可以考虑使用抽象类:

  • 你希望让许多不相关的类来实现你的接口。例如,Java中ComparableCloneable接口被许多不相关的类所实现。
  • 你希望具体指明某一特定数据类型的某个具体行为,但并不关心是谁实现了这个行为
  • 你想利用对于类型的多重继承
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • 首先看抽象类,它介于普通类和接口之间,尽管在构建某些未实现方法的类时,很多时候 往往会去创建接口,但抽象类仍然很重...
    一根烟的弹跳阅读 1,209评论 5 21
  • 一、抽象类 1、抽象方法 抽象方法只有声明,而没有具体的实现。也就是说没有{}。抽象方法的声明格式为:abstra...
    锈色的栅栏阅读 399评论 0 0
  • 说好了不熬夜,可是放假这段时间整个人像打了鸡血一样,浑身都有使不完的精力,韦先生笑称若是当初像现在这样勤奋努...
    秦雨筠阅读 636评论 0 0
  • 1、 我喜欢装配修理电器或玩具 A、符合 B、不符合 2、 我喜欢阅读科技类图书 A、...
    冯老师fy阅读 518评论 0 0
  • 在那些桂工广为流传的段子里, 专业 永远是不变的话题。 你的专业是什么呢? 资源勘查工程? 化学工程与工艺? 旅游...
    秋夜寒阅读 502评论 0 0