Java抽象接口

218

考虑一个例子(它可以在Java中编译)

public abstract interface Interface {
    public void interfacing();
    public abstract boolean interfacing(boolean really);
}

为什么接口需要声明为"抽象的"?是否还有其他规则适用于抽象接口?


最后:如果abstract是过时的,为什么它还被包括在Java中?抽象接口是否有历史背景?


可能是为什么将接口声明为抽象的?的重复。 - Thilo
5
不是重复内容,考虑到“最后:……”部分。 - aioobe
这个相关的问题引用了一个真实的例子:http://stackoverflow.com/questions/4380796/what-is-public-abstract-interface-in-java/4381308#4381308 - Raedwald
1
当你在Eclipse中“提取接口”时,为什么默认会添加“abstract”关键字? - ModdyFire
@ModdyFire,请详细说明? - Buhake Sindi
9个回答

476

为什么接口必须要“声明”为抽象的?

并不是必须这样。

public abstract interface Interface {
       \___.__/
           |
           '----> Neither this...

    public void interfacing();
    public abstract boolean interfacing(boolean really);
           \___.__/
               |
               '----> nor this, are necessary.
}

接口及其方法默认为 abstract,添加该修饰符并不会产生任何影响。

是否还有其他规则适用于抽象接口?

没有,相同的规则适用。方法必须由任何(具体的)实现类实现。

如果抽象已经过时,为什么Java中还包含它?抽象接口有历史吗?

有趣的问题。我找到了 JLS 的第一版,即使在那里也说 "This modifier is obsolete and should not be used in new Java programs"

好的,甚至 更深入地挖掘... 经过多次失败的尝试,我终于找到了原始的 Oak 0.2 Specification(或“手册”)。我必须说这是一个相当有趣的阅读,总共只有38页! :-)

在第5节“接口”下,它提供了以下示例:

public interface Storing {
    void freezeDry(Stream s) = 0;
    void reconstitute(Stream s) = 0;
}

旁边写着:

将来,接口中声明方法的“=0”部分可能会消失。

假设“=0”被“abstract”关键字替换,我猜想在某个时期,对于接口方法,使用“abstract”是强制性的!


相关文章:Java:抽象接口和抽象接口方法


3
抽象本身并不过时,对于接口可能已经过时,但仍然存在抽象类和方法。 - user85421
1
谢谢;-) 我想我终于找到了允许在接口方法前使用“abstract”的起源。 - aioobe
15
哇,所以这是“设计上的”过时。那些 JLS 设计师真的总是很害怕破坏一些东西,甚至破坏那些从未发布过的东西…… :-) - Lukas Eder
21
顺便提一句,“public”在接口声明中的方法上也是不必要的……它们总是公共的。 - rec
我尝试在Java 1.8中从我的接口中删除public,这导致我的客户端代码出错了...... 我觉得如果省略public关键字,则接口将被隐式声明为包私有 - Jonathan Benn
显示剩余5条评论

38

这不是必需的,它是可选的,就像接口方法上的public一样。

请参阅JLS:

http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html

9.1.1.1抽象接口每个接口都是隐式抽象的。 这个修饰符已经过时,不应在新程序中使用。

还有

9.4抽象方法声明

[...]

为了与旧版本的Java平台兼容,允许但不建议在接口中声明的方法中冗余指定抽象修饰符,这是一种风格问题。

对于接口方法而言,虽然可以指定public修饰符,但强烈反对这种做法作为一种风格问题。


9
给JLS:在风格上,允许但强烈不建议使用含义相同且几乎完全相同的两个句子紧挨着重复写。 - n611x007

12

不需要声明接口为抽象的。

就像将所有这些方法声明为public一样(如果接口是public,它们已经是public了)或者将它们声明为抽象(在接口中它们已经是抽象的)是多余的。

当然没有人会阻止你这么做。

其他一些可以显式声明但并非必需的内容:

  • 在构造函数的第一行调用super()
  • extends Object
  • 实现继承的接口

还有什么规则适用于抽象接口吗?

接口已经是"abstract"的。再应用该关键字没有任何区别。


2
显然,即使接口本身是包私有的,方法也可以是公共的。 - Thilo

9
请注意,在Spring中它具有非学术意义。抽象接口是对开发人员的警告,不要将其用于@Autowired。 我希望Spring / eclipse的@Autowired会查看此属性并警告/失败于此类用法。
一个真实的例子:@Service代理在@Transnational下到@Repository需要使用相同的基本方法,但是由于@Autowired,它们应该使用扩展此抽象接口的不同接口。(我称之为XXXSpec接口)

+1 好的建议,我广泛地寻找了一种非可被动态注入会话Bean的分离方法。也许我可以使用FindBugs/Checkstyle来制定规则... - Grim

3

每个接口都是隐式抽象的。
这个修饰符已经过时,不应在新程序中使用。

[Java语言规范-9.1.1.1 abstract接口]

还要注意,接口成员方法隐式地是public abstract
[Java语言规范-9.2 接口成员]

为什么这些修饰符是隐式的? 这里没有其他修饰符(甚至没有“无修饰符”修饰符)是有用的,因此您不需要显式输入它。


2
这并不是必要的,这只是语言的一个怪癖。

2

不需要这样做,因为接口默认情况下是抽象的,因为接口中的所有方法都是抽象的。


-2

抽象接口并不像每个人都所说的那样多余,至少在理论上是这样。

接口可以像类一样被扩展。如果你为应用程序设计一个接口层次结构,你可能会有一个“基础”接口,你从其他接口中扩展,但不希望它本身成为一个对象。

例如:

public abstract interface MyBaseInterface {
    public String getName();
}

public interface MyBoat extends MyBaseInterface {
    public String getMastSize();
}

public interface MyDog extends MyBaseInterface {
    public long tinsOfFoodPerDay();
}

您不希望一个类去实现MyBaseInterface接口,只想让另外两个类MMyDog和MyBoat去实现,但是这两个接口都继承了MyBaseInterface接口,所以都有了'name'属性。

我知道这有点学术性,但我认为有些人可能会觉得很有趣。:-)

在这种情况下,它实际上只是一个“标记”,用于向接口的实现者发出信号,表明它不是为单独实现而设计的。我应该指出,编译器(至少是我尝试过的sun/ora 1.6)可以编译实现抽象接口的类。


3
我相信您完全误解了我的问题。 - Buhake Sindi
3
我不同意这种推理方式。我认为每个接口都必须提供完整可用的功能集,因此每个接口都可以独立实现。 此外,编译器没有理由拒绝编译显式声明为抽象类的接口的实现类,因为所有接口都已经是隐式抽象的。否则,这将完全改变“抽象”关键字的含义。 - BladeCoder
有一天,一个“新手”会编写一个实现“MyBaseInterface”的类。你会发现很难判断这个“标记”。 - Sany Liew

-3

“抽象接口”是一种词法结构:http://en.wikipedia.org/wiki/Lexical_analysis。编译器需要它,你也可以写成interface

不要过多地涉及语言的词法结构,因为它们可能被用来解决编译过程中的一些特殊情况或向后兼容性问题,尝试关注核心的词法结构。

“接口”的本质是捕捉某些抽象概念(思想/想法/高阶思维等),其实现可能会有所不同...也就是说,可能会有多个实现。

接口是一个纯粹的抽象数据类型,代表了它所捕捉或表示的对象的特征。

特征可以通过空间或时间来表示。当它们通过空间(内存存储)表示时,这意味着你的具体类将实现一个字段和操作该字段的方法/方法,或者通过时间表示,这意味着实现该特征的任务是纯计算的(需要更多的CPU时钟进行处理),因此你需要在空间和时间之间进行特征实现的权衡。

如果您的具体类没有实现所有功能,则它会再次变成抽象类,因为您对思想或抽象性的实现不完整,您可以通过abstract类来指定它。
具体类将是一个类/一组类,它将完全捕获您尝试捕获的抽象性XYZ类。
因此,模式是:
Interface--->Abstract class/Abstract classes(depends)-->Concrete class

1
这个回答根本没有回答我的问题。还有,“看起来你是新手Java”。真的吗? - Buhake Sindi
抽象已过时 - Manish
"抽象已过时" --> 如果他们将其删除并且编译器停止识别它,则使用“抽象接口”的先前版本的源代码将无法在更新的版本中编译..他们需要保持向后兼容性。当您定义抽象接口时,接口关键字的含义与之相关联,这是更干净的版本,但对于像您这样有经验的程序员,他们提供了快捷方式“接口”..您的问题类似于i = i + 1 ==> i ++ ..选择权在您手中:D - Manish
看一下被接受的答案。我知道 abstract 在接口中已经过时了。我想知道为什么它仍然可接受,并且 abstract 接口背后的历史是什么。你正在给我一个有关抽象与接口的Java 101指南。 - Buhake Sindi
这不是词法结构,而是语法。从语义上讲,它是多余的。这不是“编译器所需的”。关于空间/时间的部分只是胡言乱语。所有这些废话都没有回答所提出的问题。不要对非代码文本使用代码格式。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接