志在指尖
用双手敲打未来

Java 接口最简单介绍

对于面向目标编程来说,笼统是一个极具魅力的特征。假设一个程序员的笼统思维很差,那他在编程中就会遇到许多困难,无法把业务变成具体的代码。在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(“\u7535\u5B50″);
}
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接口,然后具有序列化的功用。
就这么多吧,能说道这份上,我相信面试官就不会为难你了。

未经允许不得转载:IT技术网站 » Java 接口最简单介绍
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载