0中接口的含义。前言在我早期学习编程的时候,对于接口的含义确实是一头雾水。知道了接口有什么用,为什么要定义接口,感觉提前定义接口只是多余的工作。这里我先抛出一个生动的解释。有了这个解释结合全文,就可以明白接口存在的意义了:我们把电脑主板上的内存插槽、显卡插槽等比作接口。多插座呢?多么浪费机箱空间?直接用电烙铁将显卡和内存针一一焊接到主板上(手动滑稽)。估计大家看了这里大概就明白了接口的大概作用了。焊死后,如果焊错位置或拆机,需要用电烙铁拆机。多么愚蠢。全文思维导图如下:一、什么是抽象类在讲解接口之前,抽象类是一个绕不开的概念。接口可以认为是比抽象类更抽象的类。什么是抽象类?“包含一个或多个抽象方法的类是抽象类,抽象方法是没有方法体的方法。”抽象方法和抽象类都必须声明为抽象的。例如://抽象类publicabstractclassPerson{//抽象方法publicabstractStringgetDescription();}记住!“除了抽象方法,抽象类还可以包含具体数据和具体方法。”例如,抽象类Person也包含名称和一个返回名称的具体方法:程序员会认为抽象类不能包含具体方法是“错误的”。其实这也是接口和抽象类的区别。接口不能包含特定方法。?“抽象类不能被实例化”。也就是说,如果一个类被声明为抽象类,则不能创建该类的对象。newPerson("Jack");//Error可以定义一个抽象类的对象变量,但只能引用非抽象子类的对象。假设Student类是Person的非抽象子类:Personp=newStudent("Jack");//对的所谓非抽象子类就是说如果你创建一个子类继承一个抽象类并为它创建一个对象,则“必须为父类的所有抽象方法提供方法定义”。如果不这样做(你可以选择不这样做),子类仍然是一个抽象类,编译器会强制我们在新类中加上abstract关键字。下面定义了继承抽象类Person的具体子类Student:publicclassStudenttextendsPerson{privateStringmajor;publicStudent(Stringname,Stringmajor){super(name);this.major=major;}@OverridepublicStringgetDescription(){//实现父类抽象方法return"astudentmajoringin"+major;}}在Student类中实现了父类中的抽象方法getDescription。因此,“Student类中的所有方法都是非抽象的,这个类不再是抽象类”。调用如下:Personp=newStudent("Jack","ComputerScience");p.getDescription();由于无法构造抽象类Person的对象,所以变量p永远不会引用Person对象,而是引用具体的子类比如StudentClass对象,在这些对象中重写了getDescription方法。2、什么是接口接口的本质其实就是一个类,而且是比抽象类更抽象的类。怎么说?抽象类可以包含具体方法,但接口消除了这种可能性。“在Java8之前,接口非常纯粹,只能包含抽象方法,即没有方法体的方法。”在Java8中,接口发生了一些变化,开始允许接口包含默认方法和静态方法,下面会解释。Java使用关键字interface而不是class来创建接口。和类一样,我们通常在关键字interface之前加上public关键字,否则接口只有包访问权限,只能在与接口相同的包下使用。publicinterfaceConcept{voididea1();voididea2();}同样,由于接口中有抽象方法,所以需要对其进行扩展(继承)。使用implements关键字使类扩展特定接口(或一组接口)。通俗地说:接口只是形状,现在扩展子类需要解释它是如何工作的。classImplementationimplementsConcept{@Overridepublicvoididea1(){System.out.println("idea1");}@Overridepublicvoididea2(){System.out.println("idea2");}}这里需要注意的是可以选择显式声明方法接口是公开的,但“即使你不公开,它们也是公开的”。因此,在实现接口时,必须将接口中的方法定义为公共方法。否则,它们只有包访问权限,因此在继承时,它们的可访问性降低,这是Java编译器不允许的。另外,接口中允许使用常量,就像接口中的方法自动设置为public一样,“接口中的字段会自动设置为publicstaticfinal类型”,例如:publicinterfaceConcept{voididea1();//publicvoididea1();//staticattributedoubleitem=95;//apublicstaticfinalconstant}?可以将接口方法标记为public,字段标记为publicstaticfinal。有些程序员愿意出于习惯或为了提高清晰度而这样做。但Java语言规范“建议不要写这些多余的关键字”。?3.接口的特点接口和类的区别在于我们“不能像类一样使用new操作符来实例化接口”:x=newConcept(...);//ERROR原因也很简单,该接口没有具体的构造方法,一定不能实例化。当然,虽然不能构造接口的对象,但是声明接口的变量还是可以的:Conceptx;//OK接口变量必须引用实现接口的类对象:x=newImplementation(...);//OKprovidedImplementationimplementsConcept接下来,如同使用instanceof检查一个对象是否属于特定的类一样,instanceof也可以用来检查一个对象是否实现了特定的接口:if(xinstanceofConcept){...}另外,像可以建立类的继承关系,“接口也可以继承”:publicinterfaceConcept1{voididea1();voididea2();}-------------------------------------------publicinterfaceConcept2extendsConcept1{doubleidea3();}当然,你可能看了这里还是不明白。既然有了抽象类,为什么Java编程语言还要煞费苦心地引入接口的概念呢?非常重!因为“一个类可以实现多个接口,但一个类只能继承一个父类”。正是接口的出现,打破了Java单继承的局限,为定义类的行为提供了极大的灵活性。classImplementationimplementsConcept1,Concept2//OK有一个实践经验:在合理范围内尽量抽象。显然,接口比抽象类更抽象。因此,接口通常优于抽象类。4.Java8接口的新特性上面提到“在Java8中,允许在接口中添加静态方法和默认方法”。从理论上讲,没有理由认为这应该是非法的,只是它违背了将接口作为抽象规范的目的。例如:publicinterfaceConcept{//静态方法publicstaticvoidget(Stringname){System.out.println("hello"+name);}//默认方法defaultvoididea1(){System.out.println("thisisidea1");};}用default修饰符标记的方法是默认方法,这样子类就不需要实现这个方法。但是引入默认方法后,就出现了“默认方法冲突”的问题。如果在一个接口A中定义了一个方法idea作为默认方法,然后在另一个接口B或者超类C中定义了同样的方法idea,那么类D实现了这两个接口A和B(或者超类C)。所以D类中的方法idea有两个默认实现,存在冲突。为此,Java制定了一套规则来解决这种二义性问题:1)“超类优先”。如果超类提供了具体方法,则接口中同名且参数类型相同的默认方法将被忽略。2)“接口冲突”。如果一个超类接口提供了一个默认方法,而另一个超类接口也提供了一个同名和相同参数类型的方法,则子类必须重写这个方法来解决冲突。例如:interfaceA{defaultvoididea(){System.out.println("thisisA");}}interfaceB{defaultvoididea(){System.out.println("thisisB");}}//需要重写idea中的方法classDclassDimplementsA,B{publicvoidgetName(){System.out.println("thisisD");}}现在假设B接口没有为idea提供默认实现:interfaceB{voididea();}那么D类会直接继承A接口的默认方法吗?这似乎有道理,但Java设计者更强调一致性。不管两个接口怎么冲突,“只要一个接口提供了默认实现,编译器就会报错,我们必须解决这个歧义”。当然,如果两个接口都没有为共享方法提供默认实现,那么就像Java8之前一样,这里不存在冲突。5.接口的含义早期学习编程的时候,对接口的含义确实是一头雾水。自己写代码的时候,基本实现不了需要写接口。我不知道这个接口是干什么用的,为什么?定义接口,我觉得提前定义接口只是一个多余的工作。其实不是,定义一个接口也不是多余的,“接口是用来提供公共方法,指定子类的行为”。比如让大家直观感受界面的功能:比如有一个网站,需要保存不同客户的信息。有的客户来自网站,有的客户来自手机客户端,有的客户直接从后台管理系统进入。假设不同来源的客户有不同的业务流程。这个时候我们定义一个接口来提供存储客户信息的方法,然后不同的平台实现我们存储客户信息的接口。以后要保存客户信息,我们只需要知道这个接口就够了,把具体的调用方法封装到一个黑盒子里,这就是Java的多态性的体现。“接口帮助我们以统一的方式管理这些具有相同功能的方法。”再比如,我们想做一个画板程序,里面有一个panel类,主要负责画图功能,然后你定义了这个类,但是最近突然发现这个类不能满足你,然后你再去重新设计这个类,更糟糕的是,你可能不得不丢弃这个已有的类,然后其他引用这个类的地方也需要修改,这显然很麻烦。如果一开始就定义了一个接口,把绘画功能放在这个接口里面,然后在定义一个类的时候实现这个接口,那么只需要用这个接口来引用实现它的类就可以了。如果以后要修改的话,只是引用另外一个类而已。“接口的使用提高了代码的可维护性和可扩展性。”另外,从这两个例子中我们也可以看出,接口不仅“降低了代码的耦合度”,而且只描述了程序对外的服务,不涉及任何具体的实现细节,因此更加“安全”“。
