抽象类
以一个例子开始:
class Animal{
...
void run(){}
}
class Dog extends Animal{
...
void run(){}
}
class Cat extends Animal{
...
void run(){}
}
由于多态的存在,子类可以重写父类的非final方法。有时我们可能只想用子类的方法,比如上例,对于父类Animal来说,显然这是一个很抽象的类,因为Dog、Cat、Bird等都可以是Animal,Animal的run()方法如果在实际应用中没有实际意义,那么可以将它去掉,当然不是直接将该run()方法删除,那样子类的方法重写就会失去意义,正确的做法是将该方法声明为抽象方法,抽象方法没有任何方法实现语句,但本身可以被继承和重写。
abstract关键字可以将一个方法声明为抽象方法,如下:
class Animal{
...
abstract void run();
}
仅仅是这样还不够,因为如果一个类包含抽象方法,该方法由于无法被执行,包含该方法的类也是无法被实例化的,必须将该类也声明为abstract才可以,即抽象类。
即如下:
abstract class Animal{
...
abstract void run();
}
抽象类无法被实例化,但可以被继承,抽象方法也可以被重写,但不可被重载。
在抽象类中,除了可以正常的定义方法和成员变量外,还可以定义抽象方法,但由于抽象方法没有具体的执行体语句,因此它强迫子类实现其定义的抽象方法,否则编译器会报错。因此,抽象方法实际上相当于定义了“规范”。
有关抽象类的注意点:
1.抽象类不一定有抽象方法,但有抽象方法的类一定是抽象类。
2.抽象类的子类要么仍为抽象类,要么该子类必须重写抽象类中所有的抽象方法。
3.不存在抽象的构造方法。
4.不存在抽象的static方法,即static与abstract不能共存。
5.abstract与final不能共存。一个强制子类重写方法,一个禁止子类重写方法。
6.abstract与private不能共存。
接口
java中的接口是一系列方法的声明,它是一个抽象类型,是抽象方法的集合。一个接口只有方法的特征而没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为。这样,多态就能更好的发挥作用。
即接口定义完全抽象规范,类实现接口。
有关接口特性:
1.接口不是类,硬要说的话可以把它看成一个特殊的抽象类,但它与类是属于不同的概念的。
2.java接口内只允许声明方法和全局常量。所有接口方法都会被隐式的指定为public abstract 方法,所有接口中的变量都会被隐式的指定为public static final 变量。被隐式指定并不是说你可以修改它们,接口方法只能是public abstract,接口变量也只能是public static final。
3.接口无法被实例化,它也没有构造方法,但它可以被实现。一个实现接口的类,要么必须实现接口中定义的所有方法,要么就必须声明为抽象类。
4.一个类只能有一个父类,但它可以继承多个接口。接口自身也可以继承其它接口,且支持多继承。
5.接口里可以存在静态方法,接口方法也可以有方法体。(JDK1.8后新增)
接口的声明:
[可见度] interface 接口名 [extends 其它接口名]{
//全局常量
//抽象方法
}
接口的实现:
类与接口直接不是继承与被继承的关系,而是实现与被实现的关系。类实现一个接口的时候,它需要实现接口中的所有方法,否则必须将该类声明为抽象类。
类通过implements关键字实现接口,语法如下:
class 类名 implements 接口名[,其它接口名,]{
...
}
示例:
interface Animal{
int num = 100;
void run();
void eat();
}
public class Main() implements Animal {
public static void main(String[] args){
...
}
public void run(){
...
}
public void eat(){
...
}
}
注意run()方法以及eat()方法在类中实现时必须指定为public,接口中的常量被所有类共享。
default方法与static方法:
在JDK1.8之后,接口中的方法可以有方法体,不过需要定义为default方法或者static方法。目的是当我们需要给接口新增一个方法时,会设计到全部子类。但如果新增的是default方法或者static方法,那么子类就不必全部修改,只需要在接口中作相应改变即可。
示例:
interface Animal{
void run();
String food = "rice";
default void eat(){ //default方法
System.out.println("The food is " + food + ".");
}
}
public class Main implements Animal{
public static void main(String[] args){
Main mn = new Main();
mn.eat(); //调用Main类中的eat方法
}
public void run(){
System.out.println("run!!!");
}
}
注意:default方法只能通过继承了接口的类的实例化对象调用,而static方法只能通过接口名来调用。
接口的作用:
#1 使项目分离,所有层面都面向接口开发,提高开发效率。
#2 使代码之间的耦合度降低,变得可拔插,可随意切换。
#3 接口和抽象类类似,优先选择接口,是因为接口更加抽象,且接口可多实现多继承。抽象类中还有可能存在非final变量,但接口可以杜绝这一点。
接口有助于多态的实现,因为接口类型可以用来声明一个变量,该变量可以是一个空指针,或是指向某个以此接口实现的对象。也就是说,实现了某个接口的子类,其本身类型已经不仅仅是该类型了,它也可以是接口类型,因此用接口类型的引用变量指向该子类型同样可以调用该子类中的方法。
关于接口的理解还可以参考这篇博客:
https://blog.csdn.net/qq_19782019/article/details/80259836
讲的很好,通俗易懂。