抽象类和接口
1. 为什么需要抽象?
public class Pet {
private String name;
private int health;
private int love;
public void print() {
}
// 省略getter/setter 方法
}
在子类中重写父类中继承过来的方法。
public class Penguin extends Pet {
private String gender;
@Override
public void print() {
// .....
}
// ...
}
Penguin penguin = new Penguin();
penguin.print();
上述情况如果 Penguin 完全覆盖了父类对应方法的实现,会产生一种父类对应方法没有意义,多余的感觉。
但是学了多态之后,明白这是不允许去除的!
Pet pet = new Penguin();
// 在执行此方法时,会执行子类重写后的!
pet.print();
有些时候,父类中对应方法的实现完全没有价值,子类在重写时都没有用到父类的实现,这个时候就可以使用抽象来优化。
2. 抽象的使用
在方法和类前添加 abstract
关键字,来将方法和类变为抽象的。
// 抽象类
public abstract class Pet {
private String name;
private int health;
private int love;
/**
* 宠物自白
*/
// 抽象方法
public abstract void print();
// ....
}
抽象的注意事项:
- 方法变为抽象之后,不需要再写方法体。
- 一个类中如果有抽象方法,那么类也必须变为抽象类。(抽象类一定有抽象方法?不一定!)
- 抽象类将不允许直接创建对象!哪怕你写了构造方法,也不允许,一般这类构造方法是用于给子类使用的。 同样一般抽象类是作为基类(基础类)使用的。
- 父类如果有抽象方法,子类继承后必须重写(实现)该方法,否则子类也必须为抽象类。(理解为:父债子偿)
- 抽象类不影响作为多态使用!
3. 抽象类和抽象方法
抽象类:抽象类是不完整的,它只能用作基类。在面向对象方法中,抽象类主要用来进行类型隐藏和充当全局变量的角色。
不影响抽象类作为多态使用! Pet pet = new Penguin();
public abstract class 类名 {
}
抽象方法:没有方法体
public abstract 返回值类型 方法名(形式参数列表);
4.接口的作用
接口的诞生是为了不足 Java 中无法实现多继承的情况,有了接口可以极大提升程序的扩展性!
Java 中是单根继承,当多个子类拥有共同的行为和属性时,可以抽取到父类中,然后继承即可得到这些信息。(父类:亲爹,只能有一个)
子类 is a 父类
SecurityDoor is a Door
但当部分子类又拥有共同的行为时,不可以再定义另一个父类,但是可以定义另一个父接口甚至多个父接口,父接口中定义好这些共有的行为。(父接口:干爹,可以有多个)
子类 has a 父接口
SecurityDoor has a Lock
5. 接口的语法
// 接口、父类(干爹)
public interface 接口名 {
// 属性:公共的静态常量
[public static final] 数据类型 变量名 = 变量值;
// 方法:公共的抽象方法
[public abstract] 返回值类型 方法名(形式参数列表);
// Java 8 允许使用 default 关键字来编写默认的实现内容
default 返回值类型 方法名(形式参数列表) {
}
}
// 实现类实现接口
public class 类名 implements 接口名, ... {
}
6. 接口的注意事项
-
接口中定义的属性都是 public static final 修饰的。
-
接口中定义的方法都是 public abstract 修饰的。
-
一个类可以实现多个接口。(多继承)
-
接口之间也可以进行继承。 public interface xxx接口 extends xxx接口
-
接口和实现类之间,也是这种继承关系,也可以用于多态。
Lock lock = new SecurityDoor();
-
接口是无法实例化。(创建对象)
-
实现类在实现接口时,必须和接口拥有 has a 的关系。
7. 抽象类和接口的区别
相同点:
- 代表系统的抽象层
- 不能实例化
- 都可以拥有抽象方法
不同点:
- 抽象类可以写普通属性,接口中只能放静态常量
- 抽象类只能被单继承,但接口可以多实现
- 抽象类虽然不能实例化但可以写构造方法,接口不能
- 一般接口是用来表示行为的聚合父类,而类呢是用来表示属性和行为的聚合父类。
8. 匿名内部 类
我们知道抽象类不能创建对象,但下方是什么情况?
实际上创建的是Door子类的对象,只不过这个子类没名字,所以这个类模板不能复用。
Door door = new Door() {
@Override
public void open() {
// TODO Auto-generated method stub
}
@Override
public void close() {
// TODO Auto-generated method stub
}
};
实际上它等价于。
public class SecurityDoor extends Door{
@Override
public void open() {
// TODO Auto-generated method stub
}
@Override
public void close() {
// TODO Auto-generated method stub
}
}
Door door = new SecurityDoor();