簡體   English   中英

接口與類中的內部類

[英]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();

而且,“非靜態”內部類將具有對其外部類的隱式引用。 “靜態”嵌套類不是這種情況。

如果在接口中聲明嵌套類,則它始終是publicstatic 所以:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM