抽象类以及接口的区别
先来说说抽象类
抽象方法所在的类,一定是抽象类,而抽象类中未必一定要有抽象方法。
在class之前写上abstract即是抽象类。
其次是抽象方法
就是在方法名之前加入abstract关键字,然后去掉大括号,直接以分号结束。
接口中的抽象方法类型可以是任意修饰符,java8之前接口中的方法只能是public类型,java9支持private类型。
例如:
public abstract class Animal(){ //抽象类
// 抽象方法(BTW 就算没有该方法,此类还是抽象类)
public abstract void eat();
// 普通的成员方法
public void drink(){
}
}
如何使用抽象类和抽象方法
1、不能直接创建new抽象类对象。
2、必须用一个子类来继承抽象父类。
3、子类必须覆盖重写抽象父类当中所有的抽象方法。(子类去掉抽象方法的abstract关键字,然后补上方法体大括号)
4、创建子类对象进行使用。
接上例:
// 子类继承抽象父类
public class Targer extends Animal(){
//子类覆盖重写父类当中的所有抽象方法
public void eat(){
System.out.println("吃肉");
}
}
public class Demo(){
public static void main(String[] args){
//创建子类对象进行使用
Targer targer = new Targer();
targer.eat(); //吃肉
}
}
注意事项
1、抽象类不能创建对象,只能创建其非抽象子类的对象。
2、抽象类中可以有构造方法是供子类创建对象时,初始化父类成员使用的。
3、抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
4、抽象类中的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非子类也是抽象类。
设计思想
抽象类是自下而上的抽象过程,抽象类提供了通用实现,是对某一类事物的抽象。我们在写实现类的时候,发现某些实现类具有几乎相同的实现,因此我们将这些相同的实现抽取出去成为抽象类,然后如果有一些差异点,则可以提供抽象方法来支持自定义实现。
错题纠正
抽象类自身可以定义成员而接口不可以 (×)
抽象类可以定义普通成员变量而接口不可以,但是抽象类和接口都可以定义静态成员变量,只是接口的静态成员变量要用public static final来修饰。
再来说说接口
接口就是多个类的公共规范。
接口是一种引用数据类型,最重要的内容就是其中的:抽象方法。
在java 7,接口中可以包含的内容:
1、常量
2、抽象方法
在java 8,接口中可以额外包含的内容:
3、默认方法
4、静态方法(不能通过接口实现类的对象来调用)
在java 9,接口中还可以额外包含的内容:
5、私有方法
在任何版本的java中,接口都能定义抽象方法。
注意事项:
1、接口当中的方法,修饰符必须是两个固定的关键字:public abstract
2、这两个关键字修饰符,可以选择性地忽略。
3、方法的三要素,可以随意定义。
例如:
public interface MyInterfaceAbstract{
// 以下都是抽象方法
public abstract void methodAbs1();
abstract void methodAbs2();
public void methodAbs3();
void methodAbs4();
//默认方法
public default void methodDefault(){
System.out.println("默认方法");
}
//静态方法
public static void methodStatic(){
System.out.println("静态方法");
}
//接口当中也可以定义“成员变量”,但是必须使用public static final 三个关键字进行修饰。也就是接口的常量。
/**
注意事项:
1、接口当中的常量,可以省略public static final
2、接口当中的常量,必须进行赋值,不能不赋值。
3、接口中常量的名称,使用完全大写的字母,用下划线进行分割。(推荐写法)
**/
public static abstract int NUM_OF_MY_CLASS = 12;
}
接口使用步骤:
1、接口不能直接使用,必须有一个“实现类”来“实现”该接口。
2、接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。
实现:去掉abstract关键字,加上方法体大括号。
3、创建实现类的对象,进行使用。
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类必须也是抽象类。
接上例
public class MyInterfaceAbstractImpl implements MyInterfaceAbstract{
//MyInterfaceAbstract的实现类,重写所有抽象方法
@Override
public void methodAbs1(){
System.out.println("No.1");
}
@Override
public void methodAbs2(){
System.out.println("No.2");
}
@Override
public void methodAbs3(){
System.out.println("No.3");
}
@Override
public void methodAbs4(){
System.out.println("No.4");
}
}
public class Demo02{
public static void main(String[] args){
//创建实现类的对象,进行使用
MyInterfaceAbstractImpl impl = new MyInterfaceAbstractImpl();
impl.methodAbs1();
impl.methodAbs2();
impl.methodAbs3();
impl.methodAbs4();
//调用默认方法,如果实现类中没有,会向上找接口
impl.methodDefault();//输出:“默认方法”
//impl.methodStatic(); 错误写法
//只能通过接口名称来调用静态方法
MyInterfaceAbstract.methodStatic(); //输出:“静态方法”
//访问接口中的常量
System.out.println(MyInterfaceAbstract.NUM_OF_MY_CLASS); //12
}
}
设计思想:
接口是自上而下的抽象过程,接口规范了某些行为,是对某一行为的抽象。我需要这个行为,我就去实现某个接口,但是具体怎么实现这个行为,完全是由自己决定的。
网上有一个说法挺形象的:
抽象类像叔伯,有一部分会给你,还能指导你做事的方法。
接口像干爹,可以给你指引方法,但是做成啥样得看你自己的努力成果。
普通类就是亲爹,他有啥你有啥。