美文网首页
Java中的类,抽象类和接口

Java中的类,抽象类和接口

作者: lulu_6c14 | 来源:发表于2019-02-19 14:43 被阅读0次

想必大家对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接口被许多不相关的类所实现。
  • 你希望具体指明某一特定数据类型的某个具体行为,但并不关心是谁实现了这个行为
  • 你想利用对于类型的多重继承

相关文章

  • Java基础-抽象类和接口

    抽象类和接口也是 Java 面试中常考的,下面就来总结一下抽象类和接口的相关知识。 抽象类是类,Java 中类是单...

  • 接口类&抽象类

    java的接口类和抽象类的特点 java中抽象类的特点: 抽象类和抽象方法必须用关键字abstract修饰 2.如...

  • java抽象类和接口小记

    Java抽象类和接口小记 Java抽象类和接口实现了java的多态.多态是面向对象程序语言的核心,在项目开发过程中...

  • 第18条:接口优于抽象类

    java中可以用来定义允许多个实现的类型有两种:接口和抽象类。 接口和抽象类的区别: 1,抽象类中可以存在某些方法...

  • Java抽象类和接口类

    Java中接口和抽象类的区别是什么?什么时候用接口?什么时候用抽象类?抽象类和接口存在的意义是什么?能解决哪些编程...

  • Java8以后,抽象类和接口该怎么选?

    本文将对jdk1.8以后的接口和抽象类进行讨论,假定读者已经了解java中接口(interface)和抽象类(ab...

  • java中级开发必知

    (一)Java 1.接口和抽象类的区别 ①抽象类里可以有构造方法,而接口内不能有构造方法。 ②抽象类中可以有普通成...

  • 杂七杂八学习巩固

    Java中抽象类和接口类 在抽象类中的方法不一定是抽象方法,含有抽象方法的类必须定义成抽象类。 什么时候使用抽象类...

  • 023:接口和抽象类有什么区别?

    参考答案 在Java中可以用接口和抽象类来定义允许有多个实现的类型;不过,接口和抽象类有两个主要的不同: 抽象类允...

  • java abstract

    参考java抽象类和抽象方法Android开发:抽象类(abstract class)和接口(Interface)...

网友评论

      本文标题:Java中的类,抽象类和接口

      本文链接:https://www.haomeiwen.com/subject/kryxyqtx.html