Java中的接口和抽象类
一、介绍
抽象类:被abstract修饰的类就可以称为抽象类。抽象类可以拥有抽象方法,也就是用abstract修饰的方法,这类方法没有具体的实现结构,只是一个定义。
接口:用interface替换掉class形成的一个类似类的结构,接口里面的方法全是抽象方法,接口本身不实现任何功能。
二、抽象类
抽象类本质还是一个类,它只是多了一个特点就是可以在抽象类里面定义抽象方法,此外抽象类不能被实例化,也就是不能创建一个运行类型位抽象类的对象,看下面的例子:
1 class ceshi{ 2 public static void main(String[] args) { 3 animal a1 = new animal();//报错 4 Dog a3 = new Dog(); 5 a3.run(); 6 } 7 } 8 abstract class animal{ 9 public void speak() { 10 System.out.println("this is an animal"); 11 } 12 public abstract void run(); 13 } 14 class Dog extends animal{ 15 @Override 16 public void run() { 17 System.out.println("Dog is running"); 18 } 19 }
可以看到animal是一个抽象类,它有一个抽象方法run,Dog类继承了抽象类animal,并且实现了抽象方法run,这里有几点要注意的:
1、抽象类animal中可以有自己已经实现的方法,如第9行的speak方法,继承抽象类animal的Dog类的对象是可以直接调用这个speak方法,这与普通的继承相同。Dog也可以自己重写这个speak方法。
2、抽象类中是可以没有抽象方法的,编译器不会报错,但如果有抽象方法,继承这个抽象类的普通类必须实现所有的抽象方法,不然会报错。如果不实现,也可以将自己也定义为抽象类。
3、抽象类是不能被实例化的,也就是说它不能出现在new的后面,编译器不能为一个抽象类来分配空间。上例第三行的报错:
很明确的说明了被abstract修饰的抽象类是无法实例化的。
三、接口
《java编程思想》中有这样一句话:“interface关键字使抽象的概念更向前迈进了一步”。
在接口中任何方法都是抽象的,接口这个关键字产生了一个完全抽象的类,它根本不提供任何具体实现(上文抽象类允许拥有自己的视线方法),只允许创建者确定方法名、参数列表和返回类型。一个接口就可以让所有实现它的类看起来似乎都是一致的。
我们同样看一个例子:
1 class ceshi{ 2 public static void main(String[] args) { 3 animal a1 = new animal();//报错 4 Dog a3 = new Dog(); 5 a3.speak(); 6 } 7 } 8 9 interface animal{ 10 public void speak() ; 11 public abstract void run(); 12 } 13 class Dog implements animal{ 14 public void speak() { 15 System.out.println("this is an Dog"); 16 } 17 @Override 18 public void run() { 19 System.out.println("Dog is running"); 20 } 21 22 }
可以看到,我把animal从一个抽象类转成了接口,同样由Dog类去实现(抽象类称为继承)这个接口,同样有几个点需要关注:
1、接口里面的方法前面其实默认有三个关键词:abstract、static、final,这三个是在接口中无条件存在的,所以注意第10行和11行的对比,11行的abstrct是冗余的,而我编译器也贴心的提醒我:
2、实现了接口的类同样也必须实现其中的抽象方法,而接口里面的方法都是抽象的,所以你必须实现接口里定义的全部方法。
3、接口中只能有抽象方法,不允许有方法体的方法。
4、同样接口也是不能实例化的,也就是第三行的报错,看一下报错的原因:
这可能有点熟悉,当我们尝试着去实例化抽象类的时候也是这样的提示,说明接口其实也是默认为一个抽象类,只不过它抽象的更加彻底。
那接口中可以存在常量嘛?其实是可以的:
1 public static void main(String[] args) { 2 System.out.println(animal.x); 3 } 4 5 interface animal{ 6 int x = 0; 7 public void speak() ; 8 public abstract void run(); 9 }
拿这个例子来说,我在animal接口里定义了一个常量,虽然我只是定义了它,但同上文所说,x是一个被static和final默认修饰了的静态变量(abstract只能修饰方法和类),所以我能在主函数中利用接口的名字去调用x的值,这与普通类中的静态变量是相似的,接口同样有其静态存储空间,静态变量就说存储在里面。
三、接口和抽象类的对比
最后贴一个总结: