这两个内部类声明有什么区别?还评论优点/缺点?
案例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方法。
进一步信息: 我能够在另一个没有实现接口AT ALL的类中实例化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规范的专家请求这个答案问题而不是教科书语义学。
答案 0 :(得分:27)
static
内部类是嵌套类,非静态类称为内部类。有关更多信息,请look here。
但是,我想引用相同链接的摘录。
静态嵌套类与之交互 其外部的实例成员 类(和其他类)就像 任何其他顶级课程。有效, 静态嵌套类是行为上的 嵌套的顶级类 在另一个顶级课程 包装方便。
在第二种情况下,您没有使用static
这个词。你认为它会隐含地static
,因为它是一个接口。你是正确的假设。
您可以在接口中实例化内部类,就像静态嵌套类一样,因为它实际上是一个static
嵌套类。
Levels.Items hello = new Levels.Items();
因此,上述声明在两种情况下都有效。你的第一种情况是静态嵌套类,在第二种情况下你没有指定static
,但即使这样,它也是一个静态嵌套类,因为它在接口中。 因此,除了一个嵌套在一个类中,另一个嵌套在一个接口这一事实之外没有区别。
通常,类中的内部类不在接口中,将被实例化,如下所示。
Levels levels = new Levels();
Levels.Items items = levels.new Items();
此外,“非静态”内部类将具有对其外部类的隐式引用。 “静态”嵌套类不是这种情况。
答案 1 :(得分:15)
如果在界面中声明嵌套类,则它始终是 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;
}
答案 2 :(得分:14)
静态内部类大多类似于顶级类,除了内部类可以访问封闭类的所有静态变量和方法。封闭的类名有效地附加到内部类的包命名空间。通过将一个类声明为静态内部类,您传达的是,该类与封闭类的上下文密不可分。
非静态内部类不太常见。主要区别在于非静态内部类的实例包含对封闭类的实例的隐式引用,因此可以访问实例变量和封闭类实例的方法。这会导致一些奇怪的实例化习语,例如:
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 :(得分:7)
您给出的嵌套/内部类的示例是(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类是这个成语的一个众所周知的例子。
答案 4 :(得分:0)
恕我直言,优势是,如果你的项目文件夹变得微不足道,那么你的课程就会变得更少; 劣势是当你的内部阶级随着需求变化而增长时, maintenacne 成为你的噩梦。
答案 5 :(得分:0)
我认为第一个会声明一个类Levels和一个名为Items的静态内部类。项目可以由Levels.Items引用,并且是静态的。
虽然第二个会声明一个简单的内部类,可以使用Levels.Items访问,如下所示:
Levels.Items hello = new Levels.Items();
编辑:这是完全错误的,请阅读评论和其他回复。