在Java中,针对抽象有两种实现方式,一种是接口,一种是抽象类,有很多读者也因此对这两种实现方式比较困惑,到底是使用接口,还是使用抽象类呢?对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。
在面向对象的设计思想中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有描绘一个具体的对象,那么这样的类就是抽象类,抽象类是对那些看上去不同、但是本质上相同的具体概念的抽象,正是因为抽象的概念在问题领域没有对应的具体概念,所以抽象类是不能够实例化的。
1.基本语法区别
在Java中,接口和抽象类的定义语法是不一样的,这里以动物类为例来说明,其中定义接口的示意代码如下:
//******* Animal.java**************
package com.gongdan;
public interface Animal {
/*所有动物都会吃*/
public void eat();
/*所有动物都会飞*/
public void fly();
}
定义抽象类的示意代码如下:
//******* Animal.java**************
package com.gongdan;
public abstract class Animal {
/*所有动物都会吃*/
public abstract void eat();
/*所有动物都会飞*/
public void fly() {
……
}
}
可以看到,在接口内只能是功能的定义,而抽象类中则可以包括功能的定义和功能的实现,因此在接口中,所有的属性肯定是public static final,所有的方法都是abstract,所以可以默认不写上述标识符;而在抽象类中,则即可以包含抽象的定义,也可以包含具体的实现方法。
在具体的实现类上,接口和抽象类的实现类定义方式也是不一样的,其中接口实现类的示意代码如下:
//******* concreteAnimal.java**************
package com.gongdan;
public class concreteAnimal implements Animal {
/*所有动物都会吃*/
public void eat() {
……
}
/*所有动物都会飞*/
public void fly() {
……
}
}
抽象类的实现类示意代码如下:
//******* concreteAnimal.java**************
package com.gongdan;
public class concreteAnimal extends Animal {
/*所有动物都会吃*/
public void eat() {
……
}
/*所有动物都会飞*/
public void fly() {
……
}
}
可以看到,在接口的实现类中,使用implements标识符,而在抽象类的实现类中,则使用extends标识符。一个接口的实现类可以实现多个接口,而一个抽象类的实现类则只能实现一个抽象类。
2.设计思想区别
从前面抽象类的具体实现类的实现方式可以看出,其实在Java中,抽象类和具体实现类之间是一种继承关系,也就是说如果采用抽象类的方式,则父类和子类在概念上应该是相同的,但接口却不一样,如果采用接口的方式,则父类和子类在概念上不要求相同,接口只是抽取相互之间没有关系的类的共同特征,而不去关注类之间的关系,它可以使没有层次关系的类具有相同的行为。因此,可以这样说:抽象类是对一组具有相同属性和方法的逻辑上有关系的事物的一种抽象,而接口则是对一组具有相同属性和方法的逻辑上不相关的事物的一种抽象。
仍然以前面动物类的设计为例,来说明接口和抽象类关于设计思想的区别,该动物类默认所有的动物都具有吃的功能,其中定义接口的示意代码如下:
//******* Animal.java**************
package com.gongdan;
public interface Animal {
/*所有动物都会吃*/
public void eat();
}
定义抽象类的示意代码如下:
//******* Animal.java**************
package com.gongdan;
public abstract class Animal {
/*所有动物都会吃*/
public abstract void eat();
}
不管是实现接口,还是继承抽象类的具体动物,都具有吃的功能,具体的动物类的示意代码如下。
接口实现类的示意代码如下:
//******* concreteAnimal.java**************
package com.gongdan;
public class concreteAnimal implements Animal {
/*所有动物都会吃*/
public void eat() {
……
}
}
抽象类的实现类示意代码如下:
//******* concreteAnimal.java**************
package com.gongdan;
public class concreteAnimal extends Animal {
/*所有动物都会吃*/
public void eat() {
……
}
}
当然,具体的动物类不光具有吃的功能,比如有些动物还会飞,而有些动物却会游泳,那么该如何设计这个抽象的动物类呢?可以分别在接口和抽象类中增加飞的功能,其中定义接口的示意代码如下:
//******* Animal.java**************
package com.gongdan;
public interface Animal {
/*所有动物都会吃*/
public void eat();
/*所有动物都会飞*/
public void fly();
}
定义抽象类的示意代码如下:
//******* Animal.java**************
package com.gongdan;
public abstract class Animal {
/*所有动物都会吃*/
public abstract void eat();
/*所有动物都会飞*/
public abstract void fly();
}
但这样一来,不管是接口还是抽象类的实现类,将都具有飞的功能,这显然不能满足要求,因为只有一部分动物会飞,而会飞的却不一定是动物,比如飞机也会飞。那该如何设计呢?有很多种方案,比如再设计一个动物的接口类,该接口具有飞的功能,示意代码如下:
//******* AnimalFly.java**************
package com.gongdan;
public interface AnimalFly {
/*动物会飞*/
public void fly();
}
然后那些具体的动物类,如果有飞的功能的话,除了实现吃的接口外,再实现飞的接口,示意代码如下:
//******* concreteAnimal.java**************
package com.gongdan;
public class concreteAnimal implements Animal, AnimalFly {
/*所有动物都会吃*/
public void eat() {
……
}
/*动物会飞*/
public void fly() {
……
}
}
而那些不需要飞的功能的具体动物类只实现具体吃的功能的接口即可。另外一种解决方案是:再设计一个动物的抽象类,该抽象类具有飞的功能,示意代码如下:
//******* AnimalFly.java**************
package com.gongdan;
public abstract class AnimalFly {
/*动物会飞*/
public abstract void fly();
}
但此时就没有办法实现那些既有吃的功能又有飞的功能的具体动物类,因为在Java中具体的实现类只能实现一个抽象类。一个折中的解决办法是,让这个具有飞的功能的抽象类,继承具有吃的功能的抽象类,示意代码如下:
//******* AnimalFly.java**************
package com.gongdan;
public abstract class AnimalFly extends Animal {
/*动物会飞*/
public abstract void fly();
}
此时,对于那些只需要吃的功能的具体动物类来说,继承Animal抽象类即可,对于那些既有吃的功能又有飞的功能的具体动物类来说,则需要继承AnimalFly抽象类。
但此时对于客户端有一个问题,那就是不能针对所有的动物类都使用Animal抽象类来进行编程了,因为Animal抽象类不具有飞的功能,这不符合面向对象的设计原则,因此这种解决方案其实是行不通的。
还有另外一种解决方案,即具有吃的功能的抽象动物类用抽象类来实现,而具有飞的功能的类用接口实现,或者具有吃的功能的抽象动物类用接口来实现,而具有飞的功能的类用抽象类实现。具有吃的功能的抽象动物类用抽象类来实现,示意代码如下:
//******* Animal.java**************
package com.gongdan;
public abstract class Animal {
/*所有动物都会吃*/
public abstract void eat();
}
具有飞的功能的类用接口实现,示意代码如下:
//******* AnimalFly.java**************
package com.gongdan;
public interface AnimalFly {
/*动物会飞*/
public void fly();
}
然后既具有吃的功能又具有飞的功能的具体的动物类,则继承Animal动物抽象类,实现AnimalFly接口,示意代码如下:
//******* concreteAnimal.java**************
package com.gongdan;
public class concreteAnimal extends Animal implements AnimalFly {
/*所有动物都会吃*/
public void eat() {
……
}
/*动物会飞*/
public void fly() {
……
}
}
或者具有吃的功能的抽象动物类用接口来实现,示意代码如下:
//******* Animal.java**************
package com.gongdan;
public interface Animal {
/*所有动物都会吃*/
public void eat();
}
具有飞的功能的类用抽象类实现,示意代码如下:
//******* AnimalFly.java**************
package com.gongdan;
public abstract AnimalFly {
/*动物会飞*/
public abstract void fly();
}
然后既具有吃的功能又具有飞的功能的具体的动物类,则实现Animal动物类接口,继承AnimalFly抽象类,示意代码如下:
//******* concreteAnimal.java**************
package com.gongdan;
public class concreteAnimal extends AnimalFly implements Animal {
/*所有动物都会吃*/
public void eat() {
……
}
/*动物会飞*/
public void fly() {
……
}
}
这些解决方案有什么不同呢?再回过头来看接口和抽象类的区别:抽象类是对一组具有相同属性和方法的逻辑上有关系的事物的一种抽象,而接口则是对一组具有相同属性和方法的逻辑上不相关的事物的一种抽象,因此抽象类表示的是“is a”关系,接口表示的是“like a”关系。
假设现在要研究的系统只是动物系统,如果设计人员认为对于既具有吃的功能又具有飞的功能的具体的动物类来说,它和只具有吃的功能的动物一样,都是动物,是一组逻辑上有关系的事物,因此这里应该使用抽象类来抽象具有吃的功能的动物类,即继承Animal动物抽象类,实现AnimalFly接口。
如果设计人员认为对于既具有吃的功能,又具有飞的功能的具体的动物类来说,它和只具有飞的功能的动物一样,都是动物,是一组逻辑上有关系的事物,因此这里应该使用抽象类来抽象具有飞的功能的动物类,即实现Animal动物类接口,继承AnimalFly抽象类。
假设现在要研究的系统不只是动物系统,如果设计人员认为不管是吃的功能,还是飞的功能和动物类没有什么关系,因为飞机也会飞,人也会吃,则这里应该实现两个接口来分别抽象吃的功能和飞的功能,即实现吃的Animal接口外,再实现飞的AnimalFly接口。
从上面的分析可以看出:对于接口和抽象类的选择,反映出设计人员看待问题的不同角度,即抽象类用于一组相关的事物,表示的是“is a”的关系;而接口用于一组不相关的事物,表示的是“like a”的关系。
分享到:
相关推荐
11.java接口和抽象类的区别.zip11.java接口和抽象类的区别.zip11.java接口和抽象类的区别.zip11.java接口和抽象类的区别.zip11.java接口和抽象类的区别.zip11.java接口和抽象类的区别.zip11.java接口和抽象类的区别....
在Java编程语言中,接口(Interface)和抽象类(Abstract Class)都是用于实现多态性和代码复用的重要概念。它们都无法被直接实例化,而是位于继承结构的顶层,被其他类实现或继承。接口和抽象类都可以包含抽象方法...
### 详细解析Java中抽象类和接口的区别 #### 引言 在面向对象编程中,Java作为一种广泛应用的编程语言,提供了多种方式来实现抽象的概念。其中最常用的两种机制是抽象类(abstract class)和接口(interface)。这...
Java 接口和抽象类 Java 编程语言提供了两种机制来实现面向对象编程的多态性:接口和抽象类。这两种机制使得 Java 应用开发具有灵活性和敏捷性。 抽象类 抽象类是一种特殊的类,它不能被实例化,不能被直接使用,...
在Java编程语言中,接口(Interface)和抽象类(Abstract Class)都是用于实现多态性的关键概念,它们各自有特定的用途和优缺点。本文将深入探讨这两种概念,帮助你理解它们之间的区别以及如何在实际开发中选择使用...
在Java语言中,abstract class和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,...
10.java接口和抽象类的相似性.zip10.java接口和抽象类的相似性.zip10.java接口和抽象类的相似性.zip10.java接口和抽象类的相似性.zip10.java接口和抽象类的相似性.zip10.java接口和抽象类的相似性.zip10.java接口和...
Java中的类、抽象类和接口的区别和联系
Java接口和抽象类是两种重要的面向对象编程概念,它们在软件设计中扮演着关键角色,主要用来实现多态性和代码的可扩展性。虽然两者都用于定义类的行为,但它们之间存在着显著的区别。 首先,接口是一种完全抽象的...
在Java编程语言中,抽象类和接口是两种重要的面向对象设计概念,它们都用于实现多态性,但各自具有不同的特点和应用场景。了解并熟练掌握它们的区别对于编写高质量的Java代码至关重要。 首先,抽象类是一种不能被...
在Java语言中,abstract class 和interface 是支持抽象类定义的两种机制区别
java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例java抽象类与接口实例...
Java语言的接口与抽象类是面向对象编程中的关键概念,它们在设计模式和代码组织中起着重要作用。这里我们将深入探讨这两个概念,并分析它们的异同。 首先,接口(Interface)是Java中的一种特殊类型,它通过使用`...
在Java编程语言中,抽象类和接口是两种重要的面向对象设计概念,它们允许我们定义规范,为其他类提供模板或行为指南。让我们深入探讨这两个概念及其在Java中的应用。 首先,我们来理解抽象类。在Java中,抽象类是一...
Java中的抽象类(abstract class)和接口(interface)都是用于创建抽象化模型的重要工具,它们在面向对象编程中扮演着核心角色。这两种机制都允许我们定义一组方法的签名,但不提供具体实现,从而实现“设计契约”...
在Java编程语言中,接口(Interface)和抽象类(Abstract Class)都是用于实现多态性的关键概念,它们各自有特定的用途和特点。理解这两者的区别对于任何Java开发者来说都至关重要,因为正确地选择使用接口或抽象类...
Java抽象类与接口实验报告
综上所述,抽象类与接口在Java中各有优势和局限性。抽象类适用于提供一些基础的实现细节,而接口则更多地用于定义行为规范。理解两者之间的差异可以帮助开发者更加灵活地设计程序结构。在实际应用中,根据项目需求...