接口与类中的内部类

Ble*_*eek 28 java nested-class inner-classes static-class

这两个内部类声明有什么区别?还评论优点/缺点?

案例A:类中的类.

public class Levels {   
  static public class Items {
    public String value;
    public String path;

    public String getValue() {
      return value;}
  }
}
Run Code Online (Sandbox Code Playgroud)

和案例B:接口内的类.

public interface Levels{

  public class Items {
    public String value;
    public String path;

    public String getValue() {
      return value;}
  }
}
Run Code Online (Sandbox Code Playgroud)

纠正:放置getvalue方法.

进一步的信息:我能够在另一个没有实现接口AT ALL的类中实例化A和B两种情况下的Items类.

public class Z{//NOTE: NO INTERFACE IMPLEMENTED here!!!!
 Levels.Items items = new Levels.Items();
}
Run Code Online (Sandbox Code Playgroud)

由于接口未实例化,因此接口内的所有元素都可以通过点符号访问,而无需实例化LEVELS接口,因为您无法实例化接口 - 有效地在可渗透静态引用的接口内定义类.

所以说B案例中的Items类不是静态的没有意义.由于情况A和B都以相同的方式实例化,我不是在寻找静态或内部或嵌套的语义.停止给我关于语义的答案.我想要编译器,运行时和行为差异/优点,或者如果没有,那么就这么说.没有更多的语义答案请!!!!! JVM或.NET VM规范的专家请求这个答案问题,而不是教科书语义学.

Ade*_*ari 27

一个static内部类是一个嵌套类,且非静态称为内部类.更多信息,请看这里.

但是,我想引用相同链接的摘录.

静态嵌套类与其外部类(和其他类)的实例成员交互,就像任何其他顶级类一样.实际上,静态嵌套类在行为上是一个顶级类,它已嵌套在另一个顶级类中以方便打包.

你没有static在第二种情况下使用这个词.你认为它会隐含地是static因为它的界面.你是正确的.

您可以在接口中实例化内部类,就像静态嵌套类一样,因为它实际上是一个static嵌套类.

Levels.Items hello = new Levels.Items();
Run Code Online (Sandbox Code Playgroud)

因此,上述声明在两种情况下都有效.你的第一种情况是静态嵌套类,在第二种情况下你没有指定static,但即使这样,它也是一个静态嵌套类,因为它在接口中.因此,除了一个嵌套在类中,另一个嵌套在接口中之外,没有区别.

通常,类中的内部类(而不是接口)将被实例化,如下所示.

Levels levels = new Levels();
Levels.Items items = levels.new Items();
Run Code Online (Sandbox Code Playgroud)

而且,"非静态"内部类将具有对其外部类的隐式引用."静态"嵌套类不是这种情况.


Dan*_*art 15

如果在接口中声明嵌套类,则它始终是publicstatic.所以:

public interface Levels{
    class Items {
        public String value;
        public String path;

        public String getValue() {return value;}
    }
}
Run Code Online (Sandbox Code Playgroud)

完全一样

public interface Levels{
    public static class Items {
        public String value;
        public String path;

        public String getValue() {return value;}
    }
}
Run Code Online (Sandbox Code Playgroud)

乃至

public interface Levels{
    static class Items {
        public String value;
        public String path;

        public String getValue() {return value;}
    }
}
Run Code Online (Sandbox Code Playgroud)

我用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;


}
Run Code Online (Sandbox Code Playgroud)


Hen*_*nry 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(); 
Run Code Online (Sandbox Code Playgroud)

与静态内部类相比,非静态内部类与其封闭类密切相关.它们具有有效的用途(例如,迭代器通常在它们迭代的数据结构的类中实现为非静态内部类).

当你真的需要静态内部类行为时,声明一个非静态内部类是一个常见的错误.


Ste*_*n C 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(...);
}
Run Code Online (Sandbox Code Playgroud)

通过嵌入Response类,我们指出它是Worker API的基本部分,没有其他用途.

Map.Entry类是这个成语的一个众所周知的例子.