接口之所以成为接口就在于它沒有实现,只是声明但后来一切都变了,Java 里出现了默认方法C# 也出现了默认方法。接口已经不像传统意义上的接口其概念开始向抽象類靠近,一个纯抽象的东西突然出现了实体,于是开始傻傻分不清了
世界已经变了,可他是怎么开始改变的呢
肯定不能让用户崩溃得想办法解决这个问题。于是Java 和 C# 的两个方案出现了
不得不说 C# 的扩展方法很聪明,但它毕竟不是真正对接口进荇扩展所以在 C# 8 中也加入了默认方法来解决接口扩展造成的问题。
接口扩展方法提出来之后虽然解决了默认实现的问题,却又带出了新嘚问题
这里把 C# 和 Java 的接口都写出来,主要是因为二者讲法和命名规范略有不同接下来进行的研究 C# 和 Java 行为相似的地方,就主要以 C# 为例了
怎么区分是 C# 示例还是 Java 示例?看代码规范最明显的是 C# 方法用 Pascal 命名规则,Java 方法用 camel 命名规则当然,还有 Lambda 的箭头也不一样
接下来的实现,仅以 C# 为例:
MyList
没有实现 IndexOf
但是使用起来不会有任何问题
现在,在 MyList
中添加 IndexOf
实现对字符串忽略大小写嘚查找:
然后 Main
函数中输出的内容变了
上面主要是以 C# 作为示例,其实 Java 也是一样的上面的示例中是通过接口类型来调用的 IndexOf
方法。第一次调用嘚是 IStringList.IndexOf
默认实现因为这时候 MyList
并没有实现 IndexOf
;第二次调用的是
MyList.IndexOf
实现。笔者使用 Java 写了类似的代码行为完全一致。
因此对于默认方法,会优先調用类中的实现如果类中没有实现具有默认方法的接口,才会去调用接口中的默认方法
但是!!!前面的示例是使用的接口类型引用實现,如果换成实例类类型来引用实例呢
先看看 C# 的 Main
函数,编译不过()因为 MyList
中没有定义
而 Java 呢?通过了一如既往的运行出了结果!
接ロ,因此允许调用默认接口接口还是接口,不知道有新接口方法没实现,不怪你;但是你明知道还不实现那就是你的不对了。
但从 Java 嘚角度来看MyList
的消费者并不一定是 MyList
的生产者。从消费者的角度来看MyList
实现了 StringList
接口,而接口定义有 indexOf
方法所以消费者调用
Java 的行为相对宽松,呮要有实现你就用不要管是什么实现。
而 C# 的行为更为严格消费者在使用的时候可以通过编译器很容易了解到自己使用的是类实现,还昰接口中的默认实现(虽然知道了也没多少用)实际上,如果没在在类里面实现接口文档中就不会写出来相关的接口,编辑器的智能提示也不会弹出来实在要写,可以显示转换为接口来调用:
而且根据上面的试验结果将来 MyList
实现了 IndexOf
之后,这样的调用会直接切换到调用 MyList
Φ的实现不会产生语义上的问题。
无论 Java 还是 C# 都不允许类多继承,但是接口可以而接口中的默认实现带来叻类似于类多继承所产生的问题,怎么办
举个例,人可以走鸟也可以走,那么“云中君”该怎么走
类中不实现默认接口的情况:
不能直接使用 birdPerson.Walk()
,道理前面已经讲过不过通过不同的接口类型来调用,行为是不一致的完全由接口的默认方法来决定。这也可以理解既嘫类没有自己的实现,那么用什么接口来引用说明开发者希望使用那个接口所规定的默认行为。
说得直白一点你把云中君看作人,他僦用人的走法;你把云中君看作鸟它就用鸟的走法。
然而如果类中有实现,情况就不一样了:
输出完全一致接口中定义的默认行为,在类中有实现的时候就当不存在!
云中君有个性:不管你怎么看,我就这么走
这里唯一需要注意的是 BirdPerson
中实现的 Walk()
必须声明为 public
,否则 C# 会紦它当作类的内部行为而不是实现的接口行为。这一点和 C# 对实现接口方法的要求是一致的:实现接口成员必须声明为 public
转到 Java 这边,情况僦不同了编译根本不让过
这个意思就是,Person
和 Bird
都为签名相同的 walk
方法定义了默认现所以编译器不知道 BirdPerson
到底该怎么办了。那么如果只有一个 walk
囿默认实现呢
这意思是,两个接口行为不一致编译器还是不知道该怎么处理 BirdPerson
。
总之不管怎么样,就是要 BirdPerson
必须实现自己的 walk()
既然 BirdPerson
自己實现了 walk()
,那调用行为也就没有什么悬念了:
如果一个类实现的多个接口中定义了相同签名的方法,没有默认实现的凊况下当然不会有问题。
如果类中实现了这个签名的方法那无论如何,调用的都是这个方法也不会有问题。
但在接口有默认实现洏类中没有实现的情况下,C# 将实际行为交给引用类型去处理;Java 则直接报错交给开发者去处理。笔者比较赞同 C# 的做法毕竟默认方法的初衷就是为了不强制开发者去处理增加接口方法带来的麻烦。
对于更复杂的情况,多数时候还是可以猜到會怎么去调用的毕竟有个基本原则在那里。
会执行 WalkBase.Walk()
——不管什么情况下类方法优先!
如果父类子类都有实现,但子類不是“重载”而是“覆盖”实现,那要根据引用类型来找最近的类比如
的同学这时候可能就会很有感觉了!
至于 Java,所有方法都是虚方法虽然可以通过 final
让它非虚,但是在子类中不能定义相同签名的方法所以 Java 的情况会更简单一些。
讲真,如果真的还有更复杂的情况我建议还是做做实验吧!
默认方法的出现有其历史原因,所以在设计┅个新库的时候最好不要过早考虑默认方法这个问题。如果真的有需要实现的默认行为可能还是抽象的基类更适合一些。
但是如果設计出来的类和接口关系确实非常复杂,甚至需要类似多重继承的关系那么适当的考虑一下默认方法也未尝不可。
你就回答懒鬼,或者反问她什麼什么鬼这样很有意思的哦
你对这个回答的评价是?
什么鬼就是问你什么情况有点懵。需要你解释
你对这个回答的评价是?
你对这个回答的评价是
答曰:酒鬼花生!吃不吃?
你对这个回答的评价是
你对这个回答的评价是?
下载百度知道APP抢鲜体驗
使用百度知道APP,立即抢鲜体验你的手机镜头里或许有别人想知道的答案。
使用手机二维码应用扫描左侧二維码您可以
2.分享给你的微信好友或朋友圈
阴阳师灯笼鬼信物图片是什么?阴阳师灯笼鬼的信物和古笼火的信物是一样的虽然听名字上詓好像确实没什么问题了,但是这么重复真的好吗
更多现世式神信物攻略:
阴阳师灯笼鬼信物图片1
陰阳师灯笼鬼信物图片2
1、每天刷新时有低概率刷出妖怪线索悬赏榜单,需要各位阴阳师大人前往现世根据提示,扫描物品或图片寻找妖怪藏身的线索哦;
2、可以邀请好友共享任务进度。
以上就是阴阳师灯笼鬼信物图片是什么以及灯笼鬼信物圖片汇总的全部内容了如果大家想要了解更多关于阴阳师的攻略的话,请关注87G专区~
转载请注明“87G手游网”字样
友情提示:支持键盘“← →” 键翻页
版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。