常见问题
- 什么时候创建抽象类?什么时候创建接口?
- 它们之间的区别?
- 设计框架时该如何选择?
-- 如果以上问题在脑海中有些模糊的话,那就让我们一起带着问题来学习一下。假如与你的理解有出入或者不对的地方欢迎指出,谢谢。
1.基本概念
抽象方法:
使用abstract关键字修饰,仅有声明没有方法体的方法称为抽象方法。
public abstract void f();
抽象类:
包含抽象方法的类叫做抽象类,如果一个类包含一个或者多个抽象方法,该类必须被限定为抽象的。抽象类可能不包含抽象方法。
public abstract class TestAbstract {
private String a = "test";
abstract void test();
public String test2(){return a;}
}
接口:
接口是抽象类的一种特殊形式。使用interface修饰。
public interface TestInterface {
void test();
void test2();
}
2.案例分析
- 抽象类
我们都知道人的种类分为很多种,有黄种人、黑种人等等。他们都属于人类,它们都有一个共同的特征就是说话、走路、睡觉。从中我们不难看出人类是一个很抽象的概念,可以把人类抽象出来,他们具有共同的特征:说话、走路、睡觉。
public abstract class Human {
abstract void speak();
abstract void walk();
abstract void sleep();
}
public class YellowHuman extends Human{
@Override
void speak() {
// speak Chinese
System.out.println("YellowHuman speak Chinese");
}
@Override
void walk() { }
@Override
void sleep() {}
}
public class BlackHuman extends Human{
@Override
void speak() {// speak English
System.out.println("BlackHuman speak English");
}
@Override
void walk() { }
@Override
void sleep() {}
}
public class Test {
public static void main(String[] args) {
Human h1 = new YellowHuman();
Human h2 = new BlackHuman();
a1.speak();
a2.speak();
}
}
------------------------------------------------
output:
YellowHuman speak Chinese
BlackHuman speak English
- 抽象类是由子类具有相同的一类特征抽象而来,也可以说是其基类或者父类;
- 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public;
- 抽象类不能用来创建对象;
- 抽象方法必须由子类来实现;
- 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法,如果子类没有实现父类的抽象方法,则必须将子类也定义为抽类;
- 抽象类还是很有用的重构工具,因为它们使得我们可以很容易地将公共方法沿着继承层次结构向上移动。
- 接口
沿着上面案例,我们都知道黄种人擅长乒乓球,黑种人擅长长跑。
public interface TableTennis {
void tableTennis();
}
public interface Run {
void run();
}
public class YellowHuman extends Human implements TableTennis{
@Override
...
...
@Override
public void tableTennis() {}
}
public class BlackHuman extends Human implements Run{
@Override
...
...
@Override
public void run() {}
}
思考 ?
为什么这里没有在Human里面添加tableTennis和run的抽象方法或者接口,而是使用两个单独的接口?
public abstract class Human {
abstract void speak();
abstract void walk();
abstract void sleep();
abstract void tableTennis();
abstract void run();
}
或者
public interface class Human {
abstract void speak();
abstract void walk();
abstract void sleep();
abstract void tableTennis();
abstract void run();
}
tableTennis和run这两种行为是YellowHuman和BlackHuman各自最擅长的行为,如果抽象在Human里面,那么就会出现黄种人可能不擅长跑步,黑人可能不擅长乒乓球的情况,一旦各自擅长的东西发生改变,依赖Human的子类就会发生变化。这样就违反了面向对象设计中的核心原则 ISP (Interface Segregation Principle)。点击参考
- 接口是抽象类的延伸,Java为了保证数据安全性是不能多继承的。也就是一个类只有一个父类。但是接口不同,一个类可以同时实现多个接口,不管这些接口之间有没有关系,所以接口弥补了抽象类不能多继承的缺陷。推荐接口和抽象类同时使用,这样既保证了数据的安全性又可以实现多继承;
- 接口的所有法访问权限自动被声明为public;
- 接口中可以定义“成员变量”,会自动变为public static final修饰的。可以通过类命名直接访问:ImplementClass.name,不推荐在接口中定义成员变量;
- 实现接口的非抽象类必须实现接口中所有方法,抽象类可以不用全部实现;
- 接口不能创建对象,但可以申明一个接口变量,方便调用;
- 完全解耦,可以编写可复用性更好的代码。
3.抽象类与接口的区别
- 语法层次
public abstract class TestAbstract {
private String a = "test";
abstract void test();
public String test2(){
return a;
}
}
public interface TestInterface {
void test();
void test2();
}
在语法层次抽象类与接口的区别主要体现在写法上,且抽象类可以声明各种范围的成员,可以定义非抽象方法。接口只能声明被static final 修饰的成员变量,一般不推荐接口中声明成员变量。在某种程度上接口是抽象类的特殊化。
- 设计层次
抽象层次不同
抽象类是对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部行为进行抽象。跨域不同
抽象类所跨域的是具有相似特点的类,而接口却可以跨域不同的类。抽象类所体现的是一种继承关系,考虑的是子类与父类本质“是不是”同一类的关系。而接口并不要求实现的类与接口是同一本质,它们之间只存在”有没有“的关系。设计层次不同
抽象类是自下而上的设计,接口是自上而下。
总结
- 抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以实现多个接口。
- 抽象类表示的是"is-a"关系,接口表示的是"like-a"关系。点击参考
- 抽象类是对类抽象,而接口是对行为的抽象。