抽象类和接口
为什么需要抽象类?如何定义抽象类?
抽象类是一种模板。抽象类提供了为所有子类提供了一个通用模板。子类可以在这个模板基础上进行扩展。
通过抽象类避免了子类设计的随意性。
通过抽象类,我们可以做到严格限制子类的设计,使子类之间更加通用。
public class Test{
public static void main(String []args){
Animal animal=new Animal();//抽象类不能new 但是可以作为引用对象
}
}
abstract class Animal{
abstract void shout();
}
class Dog extends Animal{
void shout(){
System.out.println("汪汪汪");
}
void aa(){
System.out.println("喵喵");
}
}
注意:
1.abstract不能和final一起使用。
2.包含abstract方法的类必须是抽象类。用abstract修饰 class
3.abstract不能修饰属性。
4.抽象方法没有方法体
final和abstract关键字的作用
final和abstract是两个功能相反的关键字。
1)abstract可以用来修饰类和方法,不能用来修饰属性和构造方法。使用abstract修饰的类是抽象类,需要被继承,使用abstract修饰的方法是抽象方法,需要被子类继承。
2)final可以用来修饰类,方法和属性,不能修饰构造方法。使用final修饰的类不能被继承,使用final修饰的方法不能被重写,使用final修饰的变量值不能改变,所以就变成了常量。
3)final修饰基本类型的变量,其值不能更改,但是final修饰引用类型变量,栈内存的引用不能被改变,但是所指向的堆内存中的对象属性值仍可以改变。
class Test{
public static voidmain(String[]args){
final Dog dog=new Dog("小小");
dog.name="美美";//可以
dog=new Dog("大大");//不可以
}
}
抽象类和普通父类的区别:就在于包含抽象方法,抽象方法必须被子类实现,从而对子类的设计进行规范。
实现了规范和具体实现的分离,通过abstract关键字定义规范,然后要求子类必须定义具体实现。引用变量仍然可以定义为抽象类。
接口
普通类:具体的实现
抽象类:具体实现,规范(抽象方法)
接口:规范
为什么需要接口?
为什么需要接口?接口和抽象类的区别?
接口就是比"抽象类"还"抽象"的"抽象类",可以更加规范的对子类进行约束。全面的专业的实现了:规范和具体实现的分离。
抽象类还提供某些具体方法,接口不提供任何实现,接口中所有方法都是抽象方法。接口是完全面向规范,规定了一批类具有的公共方法的规范。
从接口的实现者角度看,接口定义了可以向外部提供的服务。(这里服务是由具体方法实现的)
从接口的调用者角度看,接口定义了是实现者能提供哪些服务。
接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的系统之间模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。做系统往往就是使用"面向接口"的思想来设计系统。
抽象类和子类是一种一般和特殊的关系。
接口,它和子类是实现规则的关系。
如何定义接口?
格式:
[访问修饰符] interface接口名 [extends 父接口1,父接口2....]{
常量定义
方法定于
}
访问修饰符:只能是public或默认。
接口名:和雷鸣采用相同的命名机制
extends:接口可以多继承
常量:接口中的属性只能是常量,总是:public static final修饰。
方法:接口中的方法只能是:public abstract
接口的本质:
借口就是规范,定义的是一组规范,体现了现实世界中"如果你是。。。则必须能"的思想。
接口的本质是契约,就像我们人间法律一样,制定后要遵守。
接口使用要点:
子类通过implements来实现接口中的规范
接口中不能创建实例,但是可用于声明引用变量类型。
一个类实现了接口,必须实现接口中的所有方法,并且这些方法只能是public的。
接口中只能包含静态常量,抽象方法,不能有普通属性,构造方法,普通方法。
public class Test{
public static void main(String[] args){
Volant volant=new Angel();
volant.fly();
System.out.println(Volant.FLY_HIGHT);
}
}
interface Volant{//接口
int FLY_HIGHT=100;//总是public static final
void fly();//总是public abstract void fly2();
}
interface Honest{
void helpOther();
}
class Angel implements Volant, Honest{
public void fly(){
System.out.println("我是天使,飞起来啦!");
}
public void helpOther(){
System.out.println("啦啦啦啦");
}
}
class GoodMan implements Honest{
public void helpOther(){
System.out.println("啦啦啦啦啦");
}
}
class BirdMan implements Volant{
public void fly(){
System.out.println("鸟人。会飞");
}
}
class Bird implements Volant{
public void fiy(){
System.out.println("正在飞");
}
}
class Plane implements Volant{
public void fly(){
System.out.prinln("正在飞");
}
}
接口的多继承
接口完全支持多继承。和类的继承相似,子类口扩展某个父接口,将会获得父接口中所定义的一切。
interface A{
void testa();
}
interface B{
void testb();
}
interface C extends A,B{
void testc();
}
publiv class Test implements C{
public void(){}
public void testa(){}
public void testb(){}
}
接口和抽象类的异同之处
相同点
>抽象类和接口均包含抽象方法,类必须实现所有的抽象方法,否则是抽象类
>抽象类和接口都不能实例化,他们位于继承树的顶端,用来被其他类继承和实现两者的区别主要体现两方面:语法方面和 设计理念方面
语法方面的区别是比较低层次的,非本质的,主要表现在:
>接口中只能定义全局静态常量,不能定义变量。抽象类中可以定义常量和变量。
> 接口中所有方法都是全局抽象方法。抽象类中可以有0个,1个或多喝,甚至全部都是抽象方法。
>抽象类中可以有构造方法,但不能用来实例化,而在子类实例化是执行,完成属于抽象类的初始化操作。接口中不能定义构造方法。
>一个类只能有一个直接父类(可以说抽象类),但可以充实实现多个接口。一个类使用extends来继承抽象类,使用implements来实现接口。
二者的主要区别还是在设计理念上,其决定某些情况下到底使用抽象类还是接口
>抽象类体现了一种继承关系,目的是服用代码,抽象类中定义了各个子类的相同的代码,可以认为父类是一个实现了部分功能的"中间产品",而子类是"最终产品".父类和子类之间必须存在"is-a"的关系,即父类和子类在概念本质上应该是相同的。
>接口并不要求实现类和接口在概念本质上一致的,仅仅是实现了接口定义的约定或能力而已。
接口定义了"做什么",而实现类负责完成"怎么做",体现了功能(规范)和实现分离的原则。接口和实现之间可以认为是"has-a的关系"。