java中抽象类和接口的区别?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中抽象类和接口的区别?相关的知识,希望对你有一定的参考价值。
简单来说,接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的,
另外,实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,
一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。
还有,接口可以实现多重继承,而一个类只能继承一个超类,
但可以通过继承多个接口实现多重继承,
接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用.
接口和抽象类都是继承树的上层,他们的共同点如下:
1) 都是上层的抽象层。
2) 都不能被实例化
3) 都能包含抽象的方法,这些抽象的方法用于描述类具备的功能,但是不比提供具体的实现。
他们的区别如下:
1) 在抽象类中可以写非抽象的方法,从而避免在子类中重复书写他们,这样可以提高代码的复用性,这是抽象类的优势;接口中只能有抽象的方法。
2) 一个类只能继承一个直接父类,这个父类可以是具体的类也可是抽象类;但是一个类可以实现多个接口。
Java语言中类的继承是单继承原因是:
当子类重写父类方法的时候,或者隐藏父类的成员变量以及静态方法的时候,JVM使用不同的绑定规则。
如果一个类有多个直接的父类,那么会使绑定规则变得更复杂。为了简化软件的体系结构和绑定机制,java语言禁止多继承。
接口可以多继承,是因为接口中只有抽象方法,没有静态方法和非常量的属性,
只有接口的实现类才会重写接口中方法。因此一个类有多个接口也不会增加JVM的绑定机制和复杂度。
对于已经存在的继承树,可以方便的从类中抽象出新的接口,但是从类中抽象出新的抽象类就不那么容易了,因此接口更有利于软件系统的维护和重构。
这是初学者经常会遇到的问题,看到这个问题,自己想起来以前痛苦的学习过程。
简单的回答一下。接口和抽象类之间有没有区别?可以肯定的回答:有区别。
那既然有区别,我们不妨带着疑问去探索一下,语言设计者们在设计接口和抽象类时为什么要设计出区别,他们的目的何在。
编程语言的设计其实也是一门哲学。
首先接口和抽象类的设计目的就是不一样的。接口是对动作的抽象,而抽象类是对根源的抽象。
对于抽象类,比如男人,女人这两个类,那我们可以为这两个类设计一个更高级别的抽象类--人。
对于接口,我们可以坐着吃饭,可以站着吃饭,可以用筷子吃饭,可以用叉子吃饭,甚至可以学三哥一样用手抓着吃饭,那么可以把这些吃饭的动作抽象成一个接口--吃饭。
所以在高级语言中(如Java,C#),一个类只能继承一个抽象类(因为你不可能同时是生物又是非生物)。
但是一个类可以同时实现多个接口,比如开车接口,滑冰接口,啪啪啪接口,踢足球接口,游泳接口。
总结几句话来说:
1、抽象类和接口都不能被直接实例化,如果二者要实例化,就涉及到多态,不懂多态的参见我的回答JAVA的多态用几句话能直观的解释一下吗? - 知乎。
如果抽象类要实例化,那么抽象类定义的变量必须指向一个子类对象,这个子类继承了这个抽象类并实现了这个抽象类的所有抽象方法。
如果接口要实例化,那么这个接口定义的变量要指向一个子类对象,这个子类必须实现了这个接口所有的方法。
2、抽象类要被子类继承,接口要被子类实现。
3、接口里面只能对方法进行声明,抽象类既可以对方法进行声明也可以对方法进行实现。
4、抽象类里面的抽象方法必须全部被子类实现,如果子类不能全部实现,那么子类必须也是抽象类。接口里面的方法也必须全部被子类实现,如果子类不能实现那么子类必须是抽象类。
5、接口里面的方法只能声明,不能有具体的实现。这说明接口是设计的结果,抽象类是重构的结果。
6、抽象类里面可以没有抽象方法。
7、如果一个类里面有抽象方法,那么这个类一定是抽象类。
8、抽象类中的方法都要被实现,所以抽象方法不能是静态的static,也不能是私有的private。
9、接口(类)可以继承接口,甚至可以继承多个接口。但是类只能继承一个类。
10、抽象级别(从高到低):接口>抽象类>实现类。
11、抽象类主要是用来抽象类别,接口主要是用来抽象方法功能。当你关注事物的本质的时候,请用抽象类;当你关注一种操作的时候,用接口。
12、抽象类的功能应该要远多于接口,但是定义抽象类的代价较高。
因为高级语言一个类只能继承一个父类,即你在设计这个类的时候必须要抽象出所有这个类的子类所具有的共同属性和方法;
但是类(接口)却可以继承多个接口,因此每个接口你只需要将特定的动作方法抽象到这个接口即可。
也就是说,接口的设计具有更大的可扩展性,而抽象类的设计必须十分谨慎。
在实际使用中,使用抽象类,也就是继承,是一种强耦合的设计,用来描述“A is a B” 的关系,即如果说A继承于B,那么在流程中将A当做B去使用应该完全没有问题。
比如在android中,各种控件都可以被当做View去处理。
如果在你设计中有两个类型的关系并不是“is a”,而是“is like a”,那就必须慎重考虑继承。
例如我前两天看到的一个框架中的直播流控制器(LiveStreamController)和视频控制器(CameraVideoController),
虽然它们的生命周期很类似:接受界面控制,拥有开始、停止、暂停等状态函数。
但很明显它们所掌握的资源和负责的功能都是完全不一样的,如果这时候仅仅因为长得像就觉得要去搞个“Controller”基类来归一化处理,只能是给自己找麻烦。
这两个类型很明显是一个组合的关系,即LiveStreamController持有CameraVideoController对象,根据界面传来的指令控制CameraVideoController的状态。
而接口则多用于描述各个类型的对象间所共有的行为,表示“所有实现了这个接口的类的对象都能这么干”。
非常典型的就是各种客户端编程里面的按钮点击监听(OnClickListener,TouchListener等等),
这个接口,可以由任何类型实现,表示“这个类的对象可以处理按钮点击事件”,
至于它是Activity、还是Fragment、还是匿名内部类,对于持有引用的View来说,一毛钱关系都没有,
它只要在点击事件触发时执行实现了OnClickListener的XXXX类对象的 onClick()方法,然后就执行到 onClick()方法中的实现了。
换句话说,所有实现了OnClickListener的类的对象,都可以让View “onClick”;
同理,比如我们在编写应用网络层框架的时候,所有实现了RequestCallback(自己写的回调接口)的类的对象,都可以让Request “Callback”,这就是所谓 “共有的行为”。
- 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
- 类可以实现很多个接口,但是只能继承一个抽象类
- 类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
- 抽象类可以在不提供接口方法实现的情况下实现接口。
- Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
- Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。
- 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。
本身的设计目的就是不同的。
我一直认为,工科的知识有个很明显的特点:“以用为本”。在讨论接口和抽象类的区别时,我也想从“用”的角度试着总结一下区别,所以我想到了设计目的。
接口的设计目的,是对类的行为进行约束(更准确的说是一种“有”约束,因为接口不能规定类不可以有什么行为),也就是提供一种机制,可以强制要求不同的类具有相同的行为。
它只约束了行为的有无,但不对如何实现行为进行限制。对“接口为何是约束”的理解,我觉得配合泛型食用效果更佳。
而抽象类的设计目的,是代码复用。
当不同的类具有某些相同的行为(记为行为集合A),且其中一部分行为的实现方式一致时(A的非真子集,记为B),可以让这些类都派生于一个抽象类。
在这个抽象类中实现了B,避免让所有的子类来实现B,这就达到了代码复用的目的。
而A减B的部分,留给各个子类自己实现。正是因为A-B在这里没有实现,所以抽象类不允许实例化出来(否则当调用到A-B时,无法执行)。
1.接口的所有方法都必须是抽象方法,抽象类里可以有非抽象方法
2.接口的所有方法与属性都是公有的,抽象类可以有私有的属性和方法
3.普通类如果要实现接口的话,就必须实现接口的所有方法,但可以把普通类定义为抽象类来选择性重写接口的方法.
4.对普通类而言接口的所有方法都必须被实现,而抽象类的抽象方法必须被实现,非抽象方法可以不被实现.
5.普通类可以对接口可以实现多继承,对抽象类只能继承一个,但是抽象类可以继承多个接口来实现多继承
区别大家已经说了:最主要的就是JAVA不能多继承,但是可以实现多个接口。
其它次要的比如抽象类可以有变量,接口不能有啊;接口的方法全部得是公有的,抽象类可以是私有的啊。
记住最主要的区别就行,实际情况下你写一年代码也不会写一个抽象类,接口倒是会写不少。
那个被用烂了的例子是:天鹅继承鸟类。天鹅是鸟的子类 , 天鹅可以飞,飞是一种可以可以拿出来的共同的属性,比如蜜蜂也可以飞。 这可能是含义上的区别。
抛开多继承,这俩货现实意义区别没有想象的大。
面向对象语言的出现主要是为了解决复用和封装问题。
只不过思想被慢慢拔高了。JAVA语言的设计者就是个面向对象教派的,对面向对象的理论完备性非常执着(Java里除了几个基本类型,啥都是继承Object不是?
高版本如果不是为了向前兼容,基本类型也早被包裹类替代了)。
面向对象里也分流派,上个世纪末,米国几个大师为能不能多继承打的头破血流的,n篇大旗文章,互相看不上。
不过刚才google了一下,已经很难找到了。但后来,“”面向接口编程“”这一概念逐渐被更多人接收。
因为越编写大型程序,每天要写代码的程序员越发现,协议比层次重要太多太多了,哪里有那么多父类子类啊,接口本质上是一种协议。
其实JAVA本身的类库也是越来越多的使用接口了。
举个最常见的例子: HashTable,原来就是实现了Dictionary这个抽象类。后来被HashMap代替了
而HashMap对应原来的功能是实现Map接口来完成的(当然了,想线程同步可以用ConcurentHashMap,或者sync一下)。
每种语言都有每种语言的设计思路,其实各有千秋,就拿继承来说:
其实C++就支持多继承(这也是java吐槽的),这么多C++代码,也没见出多大乱子给,程序员带来多大痛苦,python多继承,也活的好好的,多少人热爱它。
很多现代语言,比如swift,还有extension这种玩意儿, 动态的给一个类或者一个结构体挂个新的方法,也被很多程序员所接受。
Java 不支持多继承,还有专门阻止继承的 sealed 关键词存在,但也有很多拥趸。
语言设计的哲学不同,出来的语言就差很多,而这些差异又都是深入思考的结果。
活下来的流行语言,必然有它的独到之处。
以上是关于java中抽象类和接口的区别?的主要内容,如果未能解决你的问题,请参考以下文章