Java 接口最简单介绍

IT技术2年前 (2022)发布 投稿用户
0

对于面向目标编程来说,笼统是一个极具魅力的特征。假设一个程序员的笼统思维很差,那他在编程中就会遇到许多困难,无法把业务变成具体的代码。在Java中,能够经过两种方式来达到笼统的意图,一种是笼统类,别的一种便是接口。

假设你现在就想知道笼统类与接口之间的差异,我能够提前给你说一个:
一个类只能承继一个笼统类,但却能够完成多个接口。
当然了,在没有搞清楚接口究竟是什么,它能够做什么之前,这个差异了解起来会有点难度。
01、接口是什么
接口是经过interface关键字界说的,它能够包括一些常量和办法,来看下面这个示例。
publicinterfaceElectronic{
//常量
StringLED=”LED”;
//笼统办法
intgetElectricityUse();
//静态办法
staticbooleanisEnergyEfficient(StringelecttronicType){
returnelecttronicType.equals(LED);
}
//默许办法
defaultvoidprintDescription(){
System.out.println(“电子”);
}
}
1)接口中界说的变量会在编译的时分主动加上publicstaticfinal润饰符,也便是说LED变量其实是一个常量。
Java官方文档上有这样的声明:
Everyfielddeclarationinthebodyofaninterfaceisimplicitlypublic,static,andfinal.
换句话说,接口能够用来作为常量类运用,还能省掉掉publicstaticfinal,看似不错的一种挑选,对吧?
不过,这种挑选并不可取。由于接口的原意是对办法进行笼统,而常量接口会对子类中的变量造成命名空间上的“污染”。
2)没有运用private、default或许static关键字润饰的办法是隐式笼统的,在编译的时分会主动加上publicabstract润饰符。也便是说getElectricityUse()其实是一个笼统办法,没有办法体——这是界说接口的原意。
3)从Java8开端,接口中答应有静态办法,比如说isEnergyEfficient()办法。
静态办法无法由(完成了该接口的)类的目标调用,它只能经过接口的姓名来调用,比如说Electronic.isEnergyEfficient(“LED”)。
接口中界说静态办法的意图是为了供给一种简单的机制,使咱们不必创建目标就能调用办法,然后提高接口的竞争力。
4)接口中答应界说default办法也是从Java8开端的,比如说printDescription(),它始终由一个代码块组成,为完成该接口而不掩盖该办法的类供给默许完成,也便是说,无法直接运用一个“;”号来结束默许办法——编译器会报错的。
答应在接口中界说默许办法的理由是很充分的,由于一个接口可能有多个完成类,这些类就必须完成接口中界说的笼统类,不然编译器就会报错。假设咱们需求在一切的完成类中追加某个具体的办法,在没有default办法的帮助下,咱们就必须挨个对完成类进行修改。

Java


来看一下Electronic接口反编译后的字节码吧,你会发现,接口中界说的一切变量或许办法,都会主动添加上public关键字——假设你想知道编译器在背面都静静做了哪些辅佐,记住反编译字节码就对了。
publicinterfaceElectronic
{
publicabstractintgetElectricityUse();
publicstaticbooleanisEnergyEfficient(StringelecttronicType)
{
returnelecttronicType.equals(“LED”);
}
publicvoidprintDescription()
{
System.out.println(“u7535u5B50″);
}
publicstaticfinalStringLED=”LED”;
}
有些读者可能会问,“二哥,为什么我反编译后的字节码和你的不一样,你用了什么反编译东西?”其实没有什么隐秘,微信搜「缄默沉静王二」回复关键字「JAD」就能够免费获取了,超级好用。
02、界说接口的注意事项
由之前的比如咱们就能够得出下面这些结论:
接口中答应界说变量
接口中答应界说笼统办法
接口中答应界说静态办法(Java8之后)
接口中答应界说默许办法(Java8之后)
除此之外,咱们还应该知道:
1)接口不答应直接实例化。
需求界说一个类去完成接口,然后再实例化。
publicclassComputerimplementsElectronic{
publicstaticvoidmain(String[]args){
newComputer();
}
@Override
publicintgetElectricityUse(){
return0;
}
}
2)接口能够是空的,既不界说变量,也不界说办法。
publicinterfaceSerializable{
}
Serializable是最典型的一个空的接口,我之前共享过一篇文章《JavaSerializable:分明就一个空的接口嘛》,感兴趣的读者能够去我的个人博客看一看,你就了解了空接口的含义。
3)不要在界说接口的时分运用final关键字,不然会报编译错误,由于接口便是为了让子类完成的,而final阻止了这种行为。
4)接口的笼统办法不能是private、protected或许final。
5)接口的变量是隐式publicstaticfinal,所以其值无法改变。
03、接口能够做什么
1)使某些完成类具有咱们想要的功用,比如说,完成了Cloneable接口的类具有拷贝的功用,完成了Comparable或许Comparator的类具有比较功用。
Cloneable和Serializable一样,都属于符号型接口,它们内部都是空的。完成了Cloneable接口的类能够运用Object.clone()办法,不然会抛出CloneNotSupportedException。
publicclassCloneableTestimplementsCloneable{
@Override
protectedObjectclone()throwsCloneNotSupportedException{
returnsuper.clone();
}
publicstaticvoidmain(String[]args)throwsCloneNotSupportedException{
CloneableTestc1=newCloneableTest();
CloneableTestc2=(CloneableTest)c1.clone();
}
}
运行后没有报错。现在把implementsCloneable去掉。
publicclassCloneableTest{
@Override
protectedObjectclone()throwsCloneNotSupportedException{
returnsuper.clone();
}
publicstaticvoidmain(String[]args)throwsCloneNotSupportedException{
CloneableTestc1=newCloneableTest();
CloneableTestc2=(CloneableTest)c1.clone();
}
}
运行后抛出CloneNotSupportedException:
Exceptioninthread”main”java.lang.CloneNotSupportedException:com.cmower.baeldung.interface1.CloneableTest
atjava.base/java.lang.Object.clone(NativeMethod)
atcom.cmower.baeldung.interface1.CloneableTest.clone(CloneableTest.java:6)
atcom.cmower.baeldung.interface1.CloneableTest.main(CloneableTest.java:11)
至于Comparable和Comparator的用法,感兴趣的读者能够参照我之前写的别的一篇文章《来吧,一文完全搞懂Java中的Comparable和Comparator》。
http://www.itwanger.com/java/2020/01/04/java-comparable-comparator.html
2)Java原则上只支撑单一承继,但经过接口能够完成多重承继的意图。
可能有些读者会问,“二哥,为什么Java只支撑单一承继?”简单来解释一下。
假设有两个类一起承继(extends)一个有特定办法的父类,那么该办法会被两个子类重写。然后,假设你决定一起承继这两个子类,那么在你调用该重写办法时,编译器不能辨认你要调用哪个子类的办法。这也正是著名的菱形问题,见下图。
ClassC一起承继了ClassA和ClassB,ClassC的目标在调用ClassA和ClassB中重载的办法时,就不知道该调用ClassA的办法,还是ClassB的办法。
接口没有这方面的困扰。来界说两个接口,Fly会飞,Run会跑。
publicinterfaceFly{
voidfly();
}
publicinterfaceRun{
voidrun();
}
然后让一个类一起完成这两个接口。
publicclassPigimplementsFly,Run{
@Override
publicvoidfly(){
System.out.println(“会飞的猪”);
}
@Override
publicvoidrun(){
System.out.println(“会跑的猪”);
}
}
这就在某种方式上达到了多重承继的意图:实际世界里,猪的确只会跑,但在雷军的眼里,站在风口的猪就会飞,这就需求赋予这只猪更多的能力,经过笼统类是无法完成的,只能经过接口。
3)完成多态。
什么是多态呢?通俗的了解,便是同一个事件发生在不同的目标上会发生不同的成果,鼠标左键点击窗口上的X号能够关闭窗口,点击超链接却能够打开新的网页。
多态能够经过承继(extends)的联系完成,也能够经过接口的方式完成。来看这样一个比如。
Shape是表明一个形状。
publicinterfaceShape{
Stringname();
}
圆是一个形状。
publicclassCircleimplementsShape{
@Override
publicStringname(){
return”圆”;
}
}
正方形也是一个形状。
publicclassSquareimplementsShape{
@Override
publicStringname(){
return”正方形”;
}
}
然后来看测验类。
Listshapes=newArrayList<>();
ShapecircleShape=newCircle();
ShapesquareShape=newSquare();
shapes.add(circleShape);
shapes.add(squareShape);
for(Shapeshape:shapes){
System.out.println(shape.name());
}
多态的存在3个前提:
1、要有承继联系,Circle和Square都完成了Shape接口
2、子类要重写父类的办法,Circle和Square都重写了name()办法
3、父类引证指向子类目标,circleShape和squareShape的类型都为Shape,但前者指向的是Circle目标,后者指向的是Square目标。
然后,咱们来看一下测验成果:

正方形
也就意味着,虽然在for循环中,shape的类型都为Shape,但在调用name()办法的时分,它知道Circle目标应该调用Circle类的name()办法,Square目标应该调用Square类的name()办法。
04、接口与笼统类的差异
好了,关于接口的一切,你应该都搞清楚了。现在回到读者春夏秋冬的那条留言,“兄弟,说说笼统类和接口之间的差异?”
1)语法层面上
接口中不能有public和protected润饰的办法,笼统类中能够有。
接口中的变量只能是隐式的常量,笼统类中能够有恣意类型的变量。
一个类只能承继一个笼统类,但却能够完成多个接口。
2)设计层面上
笼统类是对类的一种笼统,承继笼统类的类和笼统类本身是一种is-a的联系。
接口是对类的某种行为的一种笼统,接口和类之间并没有很强的相关联系,一切的类都能够完成Serializable接口,然后具有序列化的功用。
就这么多吧,能说道这份上,我相信面试官就不会为难你了。

© 版权声明
好牛新坐标 广告
版权声明:
1、IT大王遵守相关法律法规,由于本站资源全部来源于网络程序/投稿,故资源量太大无法一一准确核实资源侵权的真实性;
2、出于传递信息之目的,故IT大王可能会误刊发损害或影响您的合法权益,请您积极与我们联系处理(所有内容不代表本站观点与立场);
3、因时间、精力有限,我们无法一一核实每一条消息的真实性,但我们会在发布之前尽最大努力来核实这些信息;
4、无论出于何种目的要求本站删除内容,您均需要提供根据国家版权局发布的示范格式
《要求删除或断开链接侵权网络内容的通知》:https://itdw.cn/ziliao/sfgs.pdf,
国家知识产权局《要求删除或断开链接侵权网络内容的通知》填写说明: http://www.ncac.gov.cn/chinacopyright/contents/12227/342400.shtml
未按照国家知识产权局格式通知一律不予处理;请按照此通知格式填写发至本站的邮箱 wl6@163.com

相关文章