如您所知,接口和抽象类之间的区别在于创建变量的可能性(仅用于接口的最终静态)和接口的多重继承的可能性。
Java 8 更新几乎抹去了这条线,只留下了上述限制。这是否意味着现在具有默认方法的接口与类有相同的痛处?
PS:这里是疮的列表:
使用继承的危险:
我们可能没有意识到,被覆盖的方法可能会在另一个超类方法中被调用,从而导致计算错误。一个典型的例子是创建一个将元素添加到 HashSet 的调用计数器 -
class InstrumentedHashSet extends HashSet{ private int addCount = 0; //Пропуск конструктора. Перейдем к сути //… public boolean add(Object o){ addCount++; super.add(o); } public boolean addAll(Collection c){ addCount+=c.size(); super.addAll(c); } //… Другие методы }InstrumentedHashSet,然后我们添加集合的大小,调用HashSet的addAll()方法,里面包含了add()方法。反过来,它调用重写的方法!结果,我们将得到一个比预期大 2 倍的数字。这种“使用自己”是一个实现细节,不能保证它不会从一个版本更改为另一个版本。这可以通过简单地循环调用 add() 来改变,但这是代码重复,通常 - 你可能会错过一些东西。此选项复杂、耗时且容易出错。
新版本中的超类可能有一些方法。假设我们有一个安全系统。我们有一个控制新元素添加的子类(重新定义方法,检查元素是否符合其中的一些规范)。一个新方法出现了,它有一个字符串,直接添加字符串。底线:保护有漏洞,系统可以被黑客入侵。
如果超类有一个在子类之一中的方法,那么,充其量,当参数不匹配时,程序将无法编译。在最坏的情况下,我们只会得到错误的结果,不知道错误在哪里。
超类中的任何缺陷都将转移到子类的 API 中,而组合允许开发隐藏这些缺陷的新 API。因此,您必须仔细考虑实施和结构,因为只有一次机会改变某些东西。有必要尝试不同的结构变体,实现。
//единственная болячка, которая не переходит:
- 我们可能会意外地继承一个根本不是为此而设计的类,要么没有记录继承,要么根本没有记录。解决方案是使此类类成为最终类,以使其不能被继承。顺便说一句,这将稍微提高速度。
这是对这个问题的全面回答(由我以一种新的方式编辑)(来源 - http://javapitstop.com/article/java-interfaces/):
在这个重要的段落中,我将强调一个极其重要的点,如果有人偶然没有注意到它。那么,接口有了定义方法的能力后,接口和抽象类有区别吗?是的。差异仍然存在。而且意义重大。
它的本质是接口仍然没有字段。既不是类字段(静态)也不是对象字段(类实例)。唯一且唯一的常量。这意味着没有接口方法可以在其调用之间保存一些东西。正式地说,界面仍然没有状态。接口方法只能存储算法的逻辑。接口仍然是语言的概念上不同的实体。并且,由于上述限制,它无法打破之前实现的逻辑。不管新的机会。这是好的和重要的。
当您覆盖在接口中指定为默认的继承类中的方法时,您不应再使用默认修饰符。而这个方法,在类中被重写,是一个成熟的类方法,有权改变类/对象变量的值。不同于它的界面版本。
让我们总结一下。因此,当我们使用 default 修饰符实现/扩展包含方法的接口时,我们有以下选项来处理这些方法中的每一个:
多重继承。
随着包含程序代码的接口方法的出现,另一个有趣的点出现了。
任何 Java 类都可以从另一个 Java 类继承。但只有一个!但是一个类可以继承和实现任意数量的 Java 接口。一个接口也可以扩展许多接口。由于接口以前不包含代码,因此没有问题。现在,正如我们已经知道的那样,因为 Java 8 接口可以包含带有代码的方法(静态和默认方法)。也就是说,已经可以称为多重继承的东西出现了。这意味着这种情况也获得了这种多重继承引入的问题(问题中列出的那些疮)。
抽象类和接口的区别
最后,为了合乎逻辑,我想简要回答接口和抽象类之间区别的神圣问题,同时考虑到 Java 8 和 Java 9 的最新趋势: