1、概述
抽象:抽象类似于归纳,总结,提炼出通用的,共有的内容。
抽象是无法亲自看到的,需要充分利用思维。抽象是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征。
例如苹果、香蕉、生梨、葡萄、桃子等,它们共同的特性就是水果。得出水果概念的过程,就是一个抽象的过程。要抽象,就必须进行比较,没有比较就无法找到共同的部分。
共同特征是指那些能把一类事物与他类事物区分开来的特征,这些具有区分作用的特征又称本质特征。因此抽取事物的共同特征就是抽取事物的本质特征,舍弃不同特征。所以抽象的过程也是一个裁剪的过程,不同的、非本质性的特征全部裁剪掉了。
所谓的共同特征,是相对的,是指从某一个刻面看是共同的。比如,对于汽车和大米,从买卖的角度看都是商品,都有价格,这是他们的共同的特征,而从其他方面来比较是,他们则是不同的。所以在抽象时,同与不同,决定于从什么角度上来抽象。抽象的角度取决于分析问题的目的。
在java语言中,我们需要在普通类的基础上扩充了一些抽象方法方法,因此出现了抽象类,抽象方法;
2、抽象方法
抽象方法:用abstract修饰的方法;只有声明,没有具体的方法实现。
当一个方法为抽象方法时,意味着这个方法必须被子类的方法所重写,否则其子类的该方法仍然是abstract的,而这个子类也必须是抽象的,即声明为abstract。声明格式如下:
abstract void get();
3、抽象类
就是不能使用new方法进行实例化的类。抽象类有点类似“模板”的作用,目的是根据其格式来创建和修改新的类。就是对事物抽象的类,例如,苹果,香蕉,鸭梨,都是水果,就可以抽象出来一个水果类,这个水果类,拥有他们所有的子类的共同特性。这个类需要加abstract进行修饰,如果一个类含有抽象方法,则称这个类为抽象类。如果一个类前用abstract关键字修饰,但是类里面并没有抽象方法,那它也是一个抽象类,只是失去了设计抽象类的意义,等于白白定义了一个抽象类,却不能用它来做任何事情。抽象类的定义就是要被继承派生的,所以没有方法也就失去了存在的意思,虽然依然叫抽象类。
具体使用如下:
创建抽象水果类,类中包括一个获取的方法。
public abstract class Fruit{
abstract String get();
}
其中水果有苹果,香蕉,鸭梨等,获取苹果:
public class Apple extends Fruit{
@Override
String get(){
return "apple"
}
}
获取香蕉:
public class Banana extends Fruit{
@Override
String get(){
return "banana"
}
}
两个类都继承Fruit类,但是拥有不同的实现。 普通的类继承之后,IDE不会强制要求重写,但是抽象类继承之后必须重写,否者编译报错。
4、接口
接口泛指供别人调用的方法或者函数。接口是对行为的抽象。
接口的定义如下:
[修饰符] interface 接口名 [extends 父接口名列表]{
[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修饰符:可选,用于指定接口的访问权限,可选值为public。如果省略则使用默认的访问权限。
接口名:必选参数,用于指定接口的名称,接口名必须是合法的Java标识符。一般情况下,要求首字母大写。
extends 父接口名列表:可选参数,用于指定要定义的接口继承于哪个父接口。当使用extends关键字时,父接口名为必选参数。
方法:接口中的方法只有定义而没有被实现
接口中的变量会被隐式地指定为public static final变量,接口中定义的变量,实现接口的类中是不能被修改的(可自行测试),并且接口中的方法必须都是抽象方法,不能有具体的实现。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。接口中的方法默认是public,定义接口中的方法可以不用写public,不能用private修饰,否则编译不过报错。
public interface Fruit(){
String get();
}
4.1接口的使用
创建类实现接口,用关键词implements,使类于接口进行关联。
public class AppleInterface implements FruitInterface {
}
如果一个非抽象类实现了某个接口,就必须实现该接口中的所有方法。抽象类实现接口的话,交由子类进行处理。 Java中允许一个类实现多个接口。
下面写个详细的例子:
public interface FruitInterface {
String eat();
}
public class AppleInterface implements FruitInterface {
@Override
public String eat() {
return "吃苹果";
}
}
5、区别对比
一套组合拳,献给大家!!!!
5.1. 相同点
- 两者都是抽象类,都不能实例化。
- interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法。
5.2. 不同点
-
interface需要实现,要用implements,而abstract class需要继承,要用extends。
-
一个类可以实现多个interface,但一个类只能继承一个abstract class。
-
interface强调特定功能的实现,而abstract class强调所属关系。
-
尽管interface实现类及abstrct class的子类都必须要实现相应的抽象方法,但实现的形式不同。interface中的每一个方法都是抽象方法,都只是声明的(declaration, 没有方法体),实现类必须要实现。而abstract class的子类可以有选择地实现:
这个选择有两点含义:
- Abastract class中并非所有的方法都是抽象的,只有那些冠有abstract的方法才是抽象的,子类必须实现。那些没有abstract的方法,在Abstrct class中必须定义方法体。
- abstract class的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以通过再次声明其方法为抽象的方式,无需实现,留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
- abstract class是interface与Class的中介。
- interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能声明private及protected的方法,不能定义方法体,也不能声明实例变量。然而,interface却可以声明常量变量,并且在JDK中不难找出这种例子。但将常量变量放在interface中违背了其作为接口的作用而存在的宗旨,也混淆了interface与类的不同价值。如果的确需要,可以将其放在相应的abstract class或Class中。
abstract class在interface及Class中起到了承上启下的作用。一方面,abstract class是抽象的,可以声明抽象方法,以规范子类必须实现的功能;另一方面,它又可以定义缺省的方法体,供子类直接使用或覆盖。另外,它还可以定义自己的实例变量,以供子类通过继承来使用。
6、使用场景
一套组合拳,献给大家!!!!
6.1. interface的应用场合
- 类与类之前需要特定的接口进行协调,而不在乎其如何实现。
- 作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识。
- 需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联系。
- 需要实现特定的多项功能,而这些功能之间可能完全没有任何联系。
6.2. abstract class的应用场合
一句话,在既需要统一的接口,又需要实例变量或缺省的方法的情况下,就可以使用它。最常见的有:
- 定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以用abstract class定义一组方法体,甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。
- 某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表示状态的变量来区别不同的关系。abstract的中介作用可以很好地满足这一点。
- 规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能
7. 总结
用代码说话:
/**
* @ClassName Fruit
* @Description 定义抽象水果类
* @Date 2019/7/4 15:26
**/
public abstract class Fruit {
abstract String get();
}
/**
* @ClassName FruitInterface
* @Description 定义水果接口,并加一个吃的方法
* @Date 2019/7/4 15:26
**/
public interface FruitInterface {
String eat();
}
/**
* @ClassName Apple
* @Description 定义苹果接口,并继承Fruit,抽象类中有获得苹果的方法,拿到并不吃
* @Date 2019/7/4 15:26
**/
public class Apple extends Fruit {
@Override
String get() {
return "apple";
}
}
/**
* @ClassName Banana
* @Description 定义香蕉接口,并继承Fruit,实现接口
* @Date 2019/7/4 15:26
**/
public class Banana extends Fruit implements FruitInterface {
@Override
String get() {
return "banana";
}
@Override
public String eat() {
return "吃香蕉";
}
}
/**
* @ClassName MainT
* @Description 测试
* @Date 2019/7/4 14:37
**/
public class MainT {
public static void main(String[] args) {
//只能拿到苹果
System.out.println(new Apple().get());
//香蕉能拿到还可以吃
System.out.println(new Banana().get());
System.out.println(new Banana().eat());
}
}
综上,抽象类的方法是一定要进行实现的,接口类可以实现也可以不实现。