接口中的内部类与类中
Posted
技术标签:
【中文标题】接口中的内部类与类中【英文标题】:Inner class in interface vs in class 【发布时间】:2010-12-23 04:13:56 【问题描述】:这两个内部类声明有什么区别?也评论一下优点/缺点?
案例 A:类中的类。
public class Levels
static public class Items
public String value;
public String path;
public String getValue()
return value;
和案例 B:接口内的类。
public interface Levels
public class Items
public String value;
public String path;
public String getValue()
return value;
更正:getvalue 方法的位置。
更多信息: 我可以在另一个完全不实现接口的类中实例化 A 和 B 的 Items 类。
public class Z//NOTE: NO INTERFACE IMPLEMENTED here!!!!
Levels.Items items = new Levels.Items();
由于没有实例化接口,因此接口内的所有元素都可以通过点表示法访问,而无需实例化 LEVELS 接口,这仅仅是因为您无法实例化接口 - 有效地使接口内定义的类对静态引用具有渗透性。
所以说如果 B 不是静态的 Items 类是没有意义的。由于案例 A 和 B 都以相同的方式实例化,因此我不是在寻找关于静态、内部或嵌套的语义。别再给我关于语义的答案了。我想要编译器、运行时和行为差异/优势,或者如果没有,那么就这么说。请不要再有关于语义的答案!!!!!!请一位 JVM 或 .NET VM 规范内部专家回答这个问题,而不是教科书语义学家。
【问题讨论】:
我不是在寻找它是称为内部类还是嵌套类的语义。我正在寻找功能差异。 @h2g2 - 仅重新格式化代码后 - 您的第二个示例不正确,您不能在接口中实现方法。或者也许大括号不在正确的位置...... 对于您显示的接口定义,我得到一个编译错误(JDK/5 和 6)“接口方法不能有主体”。您是复制/粘贴编译的代码还是只是键入它? 就个人而言,我根本不喜欢公共内部类。如果它们只被一个类使用,我将它们设为私有,如果它们被多个类使用,它们应该有自己的命名空间。我也永远不会在接口中创建内部类。我不希望/期望它像那样工作,但从来没有费心去测试。 【参考方案1】:static
内部类是嵌套类,非静态的称为内部类。更多信息,look here。
但是,我喜欢引用同一链接的摘录。
静态嵌套类与 其外部的实例成员 类(和其他类)就像 任何其他***课程。有效, 静态嵌套类在行为上是 已嵌套的***类 在另一个***课程中 包装方便。
在第二种情况下,您没有使用 static
这个词。你认为它隐含地是static
,因为它是一个接口。你的假设是对的。
您可以在界面中实例化内部类,就像静态嵌套类一样,因为它实际上是一个static
嵌套类。
Levels.Items hello = new Levels.Items();
因此,上述陈述将在您的两种情况下都有效。您的第一种情况是静态嵌套类,在第二种情况下您没有指定static
,但即使那样它也将是一个静态嵌套类,因为它在接口中。 因此,除了一个嵌套在类中,另一个嵌套在接口中这一事实之外,没有区别。
通常,类中的内部类,不在接口中,会像下面这样被实例化。
Levels levels = new Levels();
Levels.Items items = levels.new Items();
此外,“非静态”内部类将隐式引用其外部类。这不是“静态”嵌套类的情况。
【讨论】:
接口中的元素是静态的,所以第二种情况也是一个静态类。请注意,问题是一个被类包围,而另一个被接口包围。问题是在类中嵌入静态类与在接口中嵌入静态类之间的行为差异是什么。【参考方案2】:静态内部类大多类似于***类,除了内部类可以访问封闭类的所有静态变量和方法。封闭类名有效地附加到内部类的包命名空间中。通过将类声明为静态内部类,您可以传达该类与封闭类的上下文密不可分的联系。
非静态内部类不太常见。主要区别在于非静态内部类的实例包含对封闭类实例的隐式引用,因此可以访问该封闭类实例的实例变量和方法。这会导致一些看起来很奇怪的实例化习语,例如:
Levels levels = new Levels(); // first need an instance of the enclosing class
// The items object contains an implicit reference to the levels object
Levels.Items items = levels.new Items();
与静态内部类相比,非静态内部类与其封闭类的联系要紧密得多。它们有有效的用途(例如,迭代器通常在它们迭代的数据结构的类中实现为非静态内部类)。
当您真正需要静态内部类行为时,声明非静态内部类是一个常见错误。
【讨论】:
非静态内部类很常见,尤其是在图形代码中【参考方案3】:如果你在接口中声明一个嵌套类,它总是public和static。所以:
public interface Levels
class Items
public String value;
public String path;
public String getValue() return value;
和
完全一样public interface Levels
public static class Items
public String value;
public String path;
public String getValue() return value;
甚至
public interface Levels
static class Items
public String value;
public String path;
public String getValue() return value;
我已经用 javap -verbose 检查了这个,它们都产生了
Compiled from "Levels.java"
public class Levels$Items extends java.lang.Object
SourceFile: "Levels.java"
InnerClass:
public #14= #3 of #23; //Items=class Levels$Items of class Levels
minor version: 0
major version: 50
Constant pool:
const #1 = Method #4.#21; // java/lang/Object."<init>":()V
const #2 = Field #3.#22; // Levels$Items.value:Ljava/lang/String;
const #3 = class #24; // Levels$Items
const #4 = class #25; // java/lang/Object
const #5 = Asciz value;
const #6 = Asciz Ljava/lang/String;;
const #7 = Asciz path;
const #8 = Asciz <init>;
const #9 = Asciz ()V;
const #10 = Asciz Code;
const #11 = Asciz LineNumberTable;
const #12 = Asciz LocalVariableTable;
const #13 = Asciz this;
const #14 = Asciz Items;
const #15 = Asciz InnerClasses;
const #16 = Asciz LLevels$Items;;
const #17 = Asciz getValue;
const #18 = Asciz ()Ljava/lang/String;;
const #19 = Asciz SourceFile;
const #20 = Asciz Levels.java;
const #21 = NameAndType #8:#9;// "<init>":()V
const #22 = NameAndType #5:#6;// value:Ljava/lang/String;
const #23 = class #26; // Levels
const #24 = Asciz Levels$Items;
const #25 = Asciz java/lang/Object;
const #26 = Asciz Levels;
public java.lang.String value;
public java.lang.String path;
public Levels$Items();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LLevels$Items;
public java.lang.String getValue();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #2; //Field value:Ljava/lang/String;
4: areturn
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LLevels$Items;
【讨论】:
【参考方案4】:您给出的嵌套/内部类的示例是(IMO)不好的示例。此外,第二个示例不是有效的 Java,因为接口只能(隐式)声明抽象方法。这是一个更好的例子:
public interface Worker
public class Response
private final Status status;
private final String message;
public Response(Status status, String message)
this.status = status; this.message = message;
public Status getStatus() return status;
public String getMessage() return message;
...
public Response doSomeOperation(...);
通过嵌入 Response 类,我们表明它是 Worker API 的基本部分,没有其他用途。
Map.Entry 类是这个惯用语的一个众所周知的例子。
【讨论】:
Map.Entry
是一个接口。【参考方案5】:
恕我直言,优势是,如果它们是微不足道的,那么你的项目文件夹中的类就更少了; 缺点是当你的内部阶层随着需求变化而增长时,maintenacne成为你的噩梦。
【讨论】:
【参考方案6】:我认为第一个会声明一个类 Levels 和一个名为 Items 的静态内部类。项目可以由 Levels.Items 引用并且是静态的。
而第二个将声明一个简单的内部类,可以使用 Levels.Items 访问它,如下所示:
Levels.Items hello = new Levels.Items();
编辑:这是完全错误的,请阅读 cmets 和其他回复。
【讨论】:
您的第一段完全是误解。在这种情况下,不要与static
这个词混淆。
此外,您的代码 sn-p 对于 static
嵌套类完全有效。但不适用于内部阶层。因此,您的代码在您放入的上下文中变得无效。应该类似于Levels.Items items = levelsInstance.new Items();
。请注意,您不能在不实例化外部类的情况下实例化内部类。我希望这可以消除疑虑。以上是关于接口中的内部类与类中的主要内容,如果未能解决你的问题,请参考以下文章