抽象类和接口
1.抽象方法和抽象类
1.1 定义
抽象方法:使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。
抽象类:包含抽象方法的类就是抽象类。通过abstract方法定义规范,然后要求子类必须定义具体实现。通过抽象类,我们就可以做到严格限制子类的设计,便于子类之间更加通用。抽象类中可以有普通变量和普通方法以及构造方法。
1.2 基本用法
public abstract class Student { //抽象类
private String name;
abstract public void study(); //抽象方法
public Student(String name) { //有参构造方法
this.name = name;
}
public Student(){} //无参构造方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) { //测试抽象方法
Student student = new Student("xsj") { //直接实例化抽象方法,但必须同时实现抽象方法
@Override
public void study() { //只能实现抽象方法
System.out.println("好好学习,天天向上");
}
public void exam(){ //特有方法可以写,但不能用
System.out.println("笔试");
}
};
student.study();
//student.exam(); 会报错,因为抽象类中没有找到方法exam()
UniversityStu stu = new UniversityStu(); //利用子类实现父类抽象方法
stu.study();
stu.exam();
}
}
class UniversityStu extends Student{ //子类继承抽象类
@Override
public void study() { //子类必须实现父类抽象方法
System.out.println("图书馆学习");
}
public void exam(){ //子类也可以定义子类特有的方法
System.out.println("笔试");
}
}
1.3 抽象类的使用要点
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化,即不能用new来实例化抽象类
- 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用
- 抽象类只能用来被继承
- 抽象方法必须被子类实现
2.接口(interface)
接口就是规范,定义的是一组规则,体现了显示世界中“如果你是…则必须能…”的思想。接口的本质是契约。
2.1 接口的作用
接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。完全实现规范和具体实现分离。
区别:
- 普通类:具体实现
- 抽象类:具体实现,规范(抽象方法)
- 接口:规范
2.2 定义和使用接口(JDK8以前)
声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2...]{
常量定义;
方法定义;
}
定义接口的详细说明:
- 访问修饰符:只能是public或默认
- 接口名:和类名采用相同命名机制
- extends:接口可以多继承
- 常量:接口中的属性只能是常量,总是:public static final 修饰,省略也是。
- 方法:接口中的方法只能是抽象方法,总是:public abstract修饰,省略也是
要点:
- 子类通过implements来实现接口中的规范
- 接口不能创建实例,但是可用于声明引用变量类型
- 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的
- JDK8(不含8)之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法
- JDK8以后,接口中包含普通的静态方法、默认方法。
2.3 接口的使用
接口:
/**
* 这里是接口
* 由于接口构造十分简单,其他人要使用时会很困难,所以要经常写注释辽
*/
public interface Volant {
int MAX_HIGHT = 100;
void fly();
}
interface Honest{
void helpOther();
}
继承了以上接口的普通类:
public class Superman implements Volant,Honest{
@Override
public void fly() {
System.out.println("飞起来了");
}
@Override
public void helpOther() {
System.out.println("乐于助人");
}
}
测试类:
public class test {
public static void main(String[] args) {
Superman man = new Superman();
man.fly();
man.helpOther();
}
}
2.4 接口中定义静态方法和默认方法(JDK8以后)
2.4.1 静态方法
静态方法直接从属于接口(接口是一种特殊的类),可以通过接口名调用。
如果子类中定义了相同名字的静态方法,这两个方法完全不同,这个方法是直接从属于子类,可以通过子类名直接调用。
基本实现:
public class test {
public static void main(String[] args) {
A.staticMet();
Test_A.staticMet();
}
}
interface A{
public static void staticMet(){
System.out.println("接口的静态方法");
}
}
class Test_A implements A{
public static void staticMet(){
System.out.println("类的静态方法");
}
}
2.4.2 默认方法
默认方法也称为扩展方法。
只需要使用default关键字即可。
默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。默认方法可以被重写也可以不被重写。
基本实现:
interface A{
default void defaultMet(){
System.out.println("默认方法");
}
}
public class Test_A implements A{ //可以重写默认方法,也可以直接使用默认方法}
public class test { public static void main(String[] args) { Test_A a = new Test_A(); a.defaultMet(); //此处调用接口中的默认方法 }}
2.4.3 默认方法调用静态方法
因为默认方法相当于一个对象的普通方法,使用在默认方法中可以直接调用静态方法。
基本实现:
interface A{ public static void staticMet(){ System.out.println("接口的静态方法"); } default void defaultMet(){ staticMet(); //在默认方法中调用静态方法 System.out.println("默认方法"); }}
2.5 接口的多继承
接口完全支持多继承,和类的接触类似,子接口扩展某个父接口,将会获得父接口中所定义的一切。
基本实现:
public class testInterface implements C{ //由于接口C继承了接口A和接口B,接口C需要实现包含A和B的所有抽象方法 @Override public void testA() { } @Override public void testB() { } @Override public void testC() { }}interface A{ void testA();}interface B{ void testB();}interface C extends A,B{ void testC();}