Java 接口中的内部类与类中的内部类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1845731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 23:15:44  来源:igfitidea点击:

Inner class in interface vs in class

javanested-classinner-classesstatic-class

提问by Blessed Geek

What is the difference between these two innerclass declarations? Also comment on advantages/disadvantages?

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

case A: class within a class.

案例A:类中的类。

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

    public String getValue() {
      return value;}
  }
}

and case B: class within interface.

和情况 B:接口内的类。

public interface Levels{

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

    public String getValue() {
      return value;}
  }
}

Made correction: to placement of getvalue method.

更正:对 getvalue 方法的放置。

further info: I am able to instantiate Items class in both cases A and B in another class that does not implement interface AT ALL.

进一步信息:我能够在另一个完全不实现接口的类中实例化 Items 类在 A 和 B 两种情况下。

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

Since an interface is not instantiated, all the elements inside an interface are accessible by dot notation without LEVELS interface instantiated simply because you cannot instantiate an interface - effectively making a class defined inside an interface permeable to static reference.

由于接口未实例化,因此接口内的所有元素都可以通过点表示法访问,而无需实例化 LEVELS 接口,这仅仅是因为您无法实例化接口 - 有效地使在接口内定义的类对静态引用具有渗透性。

So saying that Items class in case B is not static does not make sense. Since both cases A and B are instantiated the same way, I am not looking for semantics on what is static or inner or nested. Stop giving me answers on semantics. I want the compiler, runtime and behavioural differences/advantages, or if none then say so. No more answers on semantics please!!!!! An expert on JVM or .NET VM specification innards please this answer question rather than text book semanticissiests.

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

采纳答案by Henry

Static inner classes are mostly similar to top-level classes, except the inner class has access to all the staticvariables and methods of the enclosing class. The enclosing class name is effectively appended to the package namespace of the inner class. By declaring a class as a static inner class, you are communicating that the class is somehow inseparably tied to the context of the enclosing class.

静态内部类大多类似于顶级类,除了内部类可以访问封闭类的所有静态变量和方法。封闭类名有效地附加到内部类的包命名空间。通过将一个类声明为静态内部类,您传达的是该类以某种方式与封闭类的上下文密不可分。

Non-static inner classes are less common. The main difference is that instances of a non-static inner class contain an implicit reference to an instance of the enclosing class, and as a result have access to instance variables and methods of that enclosing class instance. This leads to some odd looking instantiation idioms, for example:

非静态内部类不太常见。主要区别在于非静态内部类的实例包含对封闭类实例的隐式引用,因此可以访问该封闭类实例的实例变量和方法。这导致了一些看起来很奇怪的实例化习惯用法,例如:

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(); 

Non-static inner classes are much more intimately tied to their enclosing classes than static inner classes. They have valid uses (for example iterators are often implemented as non-static inner classes within the class of the data structure they iterate over).

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

It's a common mistake to declare a non-static inner class when you only really need the static inner class behaviour.

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

回答by Adeel Ansari

An staticinner class is a nested class, and the non-static is called an inner class. For more, look here.

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

However, I like to quote an excerpt from the same link.

但是,我喜欢引用同一链接的摘录。

A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

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

You didn't use the word staticin the second case. And you think it would implicitly be staticbecause its an interface. You are right in assuming that.

你没有static在第二种情况下使用这个词。你认为它会隐含地是static因为它是一个接口。你的假设是对的。

You can instantiate the inner class in your interface, just like a static nested class, because its really a staticnested class.

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

Levels.Items hello = new Levels.Items();

So, the above statement will be valid in both of your cases. Your first case is of static nested class, and in the second case you didn't specify static, but even then it would be an static nested class because its in the interface. Hence, no difference other then the fact that one is nested in a class, and the other in an interface.

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

Normally an inner class in a class, not in interface, would be instantiated like below.

通常,类中的内部类,而不是 interface,会像下面这样实例化。

Levels levels = new Levels();
Levels.Items items = levels.new Items();

Moreover, a "non-static" inner class will have a implicit reference to its outer class. This is not the case with "static" nested class.

此外,“非静态”内部类将隐式引用其外部类。“静态”嵌套类不是这种情况。

回答by Ricky

IMHO, advantageis that you got fewer classes cluttering your project folder if they're trivial; the disadvantageis that when your inner class get growing along the requirement change, the maintenacnebecome your nightmare.

恕我直言,优点是如果它们是微不足道的,那么您的项目文件夹中就会有更少的类;的缺点是,当你的内部类相处的需求变化越来越大,maintenacne成为你的噩梦。

回答by BlueTrin

I thought that the first one would declare a class Levels and a static inner class called Items. Items could be referenced by Levels.Items and would be static.

我认为第一个会声明一个 Levels 类和一个名为 Items 的静态内部类。项目可以被 Levels.Items 引用并且是静态的。

While the second would declare a simple inner class, which can be accessed by using Levels.Items, like in the following:

而第二个将声明一个简单的内部类,可以使用 Levels.Items 访问它,如下所示:

Levels.Items hello = new Levels.Items();

EDIT: this is totally wrong, read the comments and other replies.

编辑:这是完全错误的,请阅读评论和其他回复。

回答by Stephen C

The examples you give of nested / inner classes are (IMO) bad examples. Besides the 2nd example is not valid Java since an interface can only declare (implicitly) abstract methods. Here's a better example:

您给出的嵌套/内部类的示例是(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(...);
}

By embedding the Response class, we are indicating that it is a fundamental part of Worker API with no other uses.

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

The Map.Entry class is a well-known example of this idiom.

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

回答by Daniel Worthington-Bodart

If you declare a nested class in an interface it is always publicand static. So:

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

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

        public String getValue() {return value;}
    }
}

Is exactly the same as

完全一样

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

        public String getValue() {return value;}
    }
}

And even

乃至

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

        public String getValue() {return value;}
    }
}

I've checked this with javap -verbose and they all produce

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


}