一、抽象类
抽象类
什么是抽象类?
被abstract关键字修饰的类就是抽象类。
为什么要用抽象类?
因为有的方法不需要写实现时,就可以把该方法声明成抽象方法,而一个类如果拥有抽象方法,那这个类就必须是抽象类。
因为有的事物它是抽象概念,为避免直接去使用该类,我们就需要抽象类来描述它。
抽象类的使用
abstract,抽象关键字,可以用来修饰方法,也可以用来修饰类。
抽象方法:没有方法体的方法就是抽象方法;被abstract修饰的方法就是抽象方法。
抽象类:被abstract关键字修饰的类就是抽象类。
抽象类与普通类的区别
普通类不能有抽象方法,抽象类可以有抽象方法。
普通类能new对象,而抽象类不能。
思考题:抽象类一定有抽象方法,对吗?
不对
有抽象方法的类一定是抽象类,对吗?
对
抽象类一定要有子类去实现它,否则抽象类没有意义。
子类继承抽象类后,一定要去实现它的抽象方法,除非子类也是抽象类。
子类要实现继承链中所有的抽象方法
抽象类的注意事项:
1. 抽象类**不能创建对象**,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
> 理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
> 理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
> 理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
4. 抽象类的子类,必须重写抽象父类中**所有的**抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
> 理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
二、接口
接口
什么是接口?
在Java中,接口是一种引用数据类型,是一组抽象方法的集合体。
为什么要用接口?
因为接口可以多实现,可以弥补类只能单继承的特点。
接口的写法
//常量
数据类型 常量名 = 值;
//抽象方法
返回值 方法名();
//默认方法
default 返回值 方法名(){
}
//静态方法
static 返回值 方法名(){
}
在接口中定义抽象方法时,可以省略public abstract,接口中的方法都是公共的,不能使用其它权限修饰符。
在接口中定义常量时,可以省略public static final。
接口的使用
接口中有抽象方法,所以和抽象类一样不能直接使用,抽象类是通过子类来调用,接口是通过实现类来调用的。
实现类要实现接口中所有的抽象方法。
1.声明接口
2.编写实现类实现接口
实现类的写法
public class 类名 implements 接口{
}
//接口类型 接口名 = new 实现类();
接口中为什么要新增默认方法?
因为原本接口中只有抽象方法,所有实现类都必须实现全部的抽象方法,但如果有多个实现类方法实现一致时,仍然要重写。
所以为了弥补这个缺点,提出了默认方法。
接口中为什么要新增静态方法?
因为接口的使用每次都要编写实现类继承接口,再创建接口对象,使用起来非常麻烦,为了能让接口快速使用,所以提供了静态方法
可以在静态方法中提供获取接口对象的功能,从而达到快速使用接口。
建议使用下面方式创建接口
//接口类型 接口名 = new 实现类();(推荐)
//实现类 接口名 = new 实现类();(不推荐)
比较器
如果用Arrays.sort排序我们自己写的类型数组时,会报错。因为JVM不知道按什么规则进行比较。
所以JDK内置了2个比较接口。分别是Comparable和Comparator
Comparable:内部比较器
特点:写在类的内部,会修改目标类的代码。
Comparator:外部比较器
特点:写在独立的类中,不会对目标类造成修改。
接口的注意事项:
-
子类进行多接口实现时,如果接口常量没有重名,可以按照之前的方式进行使用;如果接口常量出现重名,就必须通过接口名调用常量。
-
子类进行多接口实现时,接口中有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。
-
子类进行多接口实现时,接口中存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
-
子类进行多接口实现时,接口中有多个默认方法时,实现类都可以选择继承使用。如果默认方法有重名的,必须重写一次。
-
当一个类既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法。