[英]Inner class in interface vs in class
這兩個內部類聲明有什么區別? 還評論優點/缺點?
案例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規范的專家請求這個答案問題而不是教科書語義學。
static
內部類是嵌套類,非靜態類稱為內部類。 更多信息, 請看這里 。
但是,我想引用相同鏈接的摘錄。
靜態嵌套類與其外部類(和其他類)的實例成員交互,就像任何其他頂級類一樣。 實際上,靜態嵌套類在行為上是一個頂級類,它已嵌套在另一個頂級類中以方便打包。
在第二種情況下,您沒有使用static
一詞。 你認為它會隱含地是static
因為它是一個接口。 你是正確的。
您可以在接口中實例化內部類,就像靜態嵌套類一樣,因為它實際上是一個static
嵌套類。
Levels.Items hello = new Levels.Items();
因此,上述聲明在兩種情況下都有效 。 你的第一種情況是靜態嵌套類,在第二種情況下你沒有指定static
,但即便如此,它也是一個靜態嵌套類,因為它在接口中。 因此,除了一個嵌套在類中,另一個嵌套在接口中之外,沒有區別 。
通常,類中的內部類( 而不是接口 )將被實例化,如下所示。
Levels levels = new Levels();
Levels.Items items = levels.new Items();
而且,“非靜態”內部類將具有對其外部類的隱式引用。 “靜態”嵌套類不是這種情況。
如果在接口中聲明嵌套類,則它始終是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;
}
靜態內部類大多類似於頂級類,除了內部類可以訪問封閉類的所有靜態變量和方法。 封閉的類名有效地附加到內部類的包命名空間。 通過將一個類聲明為靜態內部類,您傳達的是,該類與封閉類的上下文密不可分。
非靜態內部類不太常見。 主要區別在於非靜態內部類的實例包含對封閉類的實例的隱式引用,因此可以訪問實例變量和封閉類實例的方法。 這會導致一些奇怪的實例化習語,例如:
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();
與靜態內部類相比,非靜態內部類與其封閉類密切相關。 它們具有有效的用途(例如,迭代器通常在它們迭代的數據結構的類中實現為非靜態內部類)。
當你真的需要靜態內部類行為時,聲明一個非靜態內部類是一個常見的錯誤。
您給出的嵌套/內部類的示例是(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類是這個成語的一個眾所周知的例子。
恕我直言, 優點是如果你的項目文件夾變得微不足道,那么你的課程就會變得更少; 缺點是,當你的內心階層隨着需求的變化而增長時, 維持生命就成了你的噩夢。
我認為第一個會聲明一個類Levels和一個名為Items的靜態內部類。 項目可以由Levels.Items引用,並且是靜態的。
而第二個會聲明一個簡單的內部類,可以使用Levels.Items訪問,如下所示:
Levels.Items hello = new Levels.Items();
編輯:這是完全錯誤的,閱讀評論和其他答復。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.