接口(interface)和抽象类(abstract)的特点和区别
接口(interface)和抽象类(abstract)的共同点和区别
进入这个话题之前我们先思考一下以下几个问题。
1,我们为什要使用抽象类和接口?
2,使用抽象类和接口有什么好处?
3,我们在设计复杂程序时该怎么合理使用抽象类和接口?
抽象类的特点
抽象类的初衷是“抽象”,即规定这个类“是什么”,具体的实现暂不确定,是不完整的,因此不允许直接创建实例。
- 抽象类是由子类具有相同的一类特征抽象而来,也可以说是其基类或者父类
- 抽象方法必须为 public 或者 protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为 public 抽象类不能用来创建对象
- 抽象方法必须由子类来实现
- 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法,如果子类没有实现父类的抽象方法,则必须将子类也定义为抽象类
- 抽象类还是很有用的重构工具,因为它们使得我们可以很容易地将公共方法沿着继承层次结构向上移动
接口的特点
Java 为了保证数据安全性是不能多继承的,也就是一个类只有一个父类。
但是接口不同,一个类可以同时实现多个接口,不管这些接口之间有没有关系,所以接口弥补了抽象类不能多继承的缺陷。
接口是抽象类的延伸,它可以定义没有方法体的方法,要求实现者去实现。
- 接口的所有方法访问权限自动被声明为 public
- 接口中可以定义“成员变量”,会自动变为 public static final 修饰的静态常量
- 可以通过类命名直接访问:ImplementClass.name
- 不推荐使用接口创建常量类
- 实现接口的非抽象类必须实现接口中所有方法,抽象类可以不用全部实现
- 接口不能创建对象,但可以申明一个接口变量,方便调用
- 完全解耦,可以编写可复用性更好的代码
我们试着来写一下抽象类,以便更能理解抽象类的使用。
这是一个项目的目录结构
说明:Animal类是被定义成立一个抽象类,Cat类和Person类继承抽象类。Test为主函数测试类。
Animal类中的代码,这个抽象类中有两个抽象方法(eat和sleep),而study是普通方法。
package com.Abstract;
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
public void study() {
System.out.println("我要学习");
}
}
Cat类继承Animal类(抽象类),就要实现Animal类中的抽象的方法,而普通方法不用实现,代码如下
package com.Abstract;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("我是猫,我吃猫粮");
}
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("我是猫,我要睡觉");
}
}
Person类继承Animal类,也要去实现父类中的抽象方法,也可以重写父类中stydy方法。代码如下
public class Person extends Animal {
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("我是人,我要吃肉");
}
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("我是人,我要睡24小时");
}
@Override
public void study() {
// TODO Auto-generated method stub
super.study();
System.out.println("我是人,我要学习");
}
}
现在测试写一个测试类Test,代码如下
Cat cat = new Cat();
Person person = new Person();
//将两个类装进list中。
List<Animal> list = Arrays.asList(cat, person);
for (Animal animal : list) {
animal.eat();
animal.sleep();
animal.study();
System.out.println("----------------");
}
// cat.eat();
// cat.sleep();
// System.out.println("----------");
// person.eat();
// person.sleep();
// person.study();
}
}
输出结果
说明:Cat类继并实现了父类的两个抽象方法,所以也会输出父类的方法。Person 继承实现了父类的两个抽象方法,并重写了study方法,所以会输出四个结果。
我们试着来写一下接口,以便更能理接口和抽象类的区别。
这是程序的目录,Shape为接口,Rectange类和Cricle类去实现Shape,Test为测试类。
接口中定义了一个抽象方法,代码如下
package Interfance;
public interface Shape {
public abstract void say();
}
Rectange类去实现Shape接口并实现接口中的抽象方法,代码如下
package Interfance;
public class Rectange implements Shape {
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("我是长方形!");
}
}
Cricle类去实现Shape接口并实现接口中的抽象方法,代码如下
package Interfance;
public class Cricle implements Shape {
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("我是三角形!");
}
}
Test测试类去输出两个子类的结果。
package Interfance;
public class Test {
public static void main(String[] args) {
Rectange rectange = new Rectange();
Cricle cricle = new Cricle();
rectange.say();
cricle.say();
}
}
输出结果如下图
回答第文章开始第三问。
1.如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
2.如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
3.如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
上一篇: 数组的定义和使用