Java中的静态嵌套类,为什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/253492/
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-11 12:03:29  来源:igfitidea点击:

Static nested class in Java, why?

javaclassstaticmember

提问by David Turner

I was looking at the Java code for LinkedListand noticed that it made use of a static nested class, Entry.

我正在查看 Java 代码LinkedList并注意到它使用了一个静态嵌套类Entry.

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

What is the reason for using a static nested class, rather than an normal inner class?

使用静态嵌套类而不是普通内部类的原因是什么?

The only reason I could think of, was that Entry doesn't have access to instance variables, so from an OOP point of view it has better encapsulation.

我能想到的唯一原因是 Entry 无法访问实例变量,因此从 OOP 的角度来看,它具有更好的封装性。

But I thought there might be other reasons, maybe performance. What might it be?

但我认为可能还有其他原因,也许是性能。可能是什么?

Note. I hope I have got my terms correct, I would have called it a static inner class, but I think this is wrong: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html

笔记。我希望我的条款是正确的,我会称它为静态内部类,但我认为这是错误的:http: //java.sun.com/docs/books/tutorial/java/javaOO/nested.html

采纳答案by matt b

The Sun page you link to has some key differences between the two:

您链接到的 Sun 页面在两者之间有一些主要区别:

A nested class is a member of its enclosing class. Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes do not have access to other members of the enclosing class.
...

Note: 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.

嵌套类是其封闭类的成员。非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有。静态嵌套类无权访问封闭类的其他成员。
...

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

There is no need for LinkedList.Entryto be top-level class as it is onlyused by LinkedList(there are some other interfaces that also have static nested classes named Entry, such as Map.Entry- same concept). And since it does not need access to LinkedList's members, it makes sense for it to be static - it's a much cleaner approach.

有没有必要LinkedList.Entry成为顶级类,因为它是唯一使用的LinkedList(也有一些其他接口也有一个名为静态嵌套类Entry,如Map.Entry-同一个概念)。因为它不需要访问 LinkedList 的成员,所以它是静态的 - 这是一种更简洁的方法。

As Jon Skeet points out, I think it is a better idea if you are using a nested class is to start off with it being static, and then decide if it really needs to be non-static based on your usage.

正如Jon Skeet 指出的那样,我认为如果您使用嵌套类是从静态类开始,然后根据您的使用情况决定它是否真的需要非静态,这是一个更好的主意。

回答by Jon Skeet

To my mind, the question ought to be the other way round whenever you see an inner class - does it reallyneed to be an inner class, with the extra complexity and the implicit (rather than explicit and clearer, IMO) reference to an instance of the containing class?

在我看来,当你看到一个内部类时,问题应该是相反的——它真的需要是一个内部类,具有额外的复杂性和对实例的隐式(而不是显式和更清晰的,IMO)引用包含类?

Mind you, I'm biased as a C# fan - C# doesn't have the equivalent of inner classes, although it does have nested types. I can't say I've missed inner classes yet :)

请注意,我偏向于 C# 粉丝 - C# 没有等效的内部类,尽管它确实具有嵌套类型。我不能说我已经错过了内部课程:)

回答by Mark Renouf

One of the reasons for static vs. normal have to do with classloading. You cannot instantiate an inner class in the constructor of it's parent.

静态与正常的原因之一与类加载有关。您不能在其父类的构造函数中实例化内部类。

PS: I've always understood 'nested' and 'inner' to be interchangeable. There may be subtle nuances in the terms but most Java developers would understand either.

PS:我一直认为“嵌套”和“内部”是可以互换的。术语中可能存在细微差别,但大多数 Java 开发人员都可以理解。

回答by Mark Renouf

I don't know about performance difference, but as you say, static nested class is not a part of an instance of the enclosing class. Seems just simpler to create a static nested class unless you really need it to be an inner class.

我不知道性能差异,但正如你所说,静态嵌套类不是封闭类实例的一部分。创建静态嵌套类似乎更简单,除非您确实需要它作为内部类。

It's a bit like why I always make my variables final in Java - if they're not final, I know there's something funny going on with them. If you use an inner class instead of a static nested class, there should be a good reason.

这有点像为什么我总是在 Java 中使我的变量成为 final - 如果它们不是 final,我知道它们会发生一些有趣的事情。如果您使用内部类而不是静态嵌套类,则应该有充分的理由。

回答by matt b

Well, for one thing, non-static inner classes have an extra, hidden field that points to the instance of the outer class. So if the Entry class weren't static, then besides having access that it doesn't need, it would carry around four pointers instead of three.

嗯,一方面,非静态内部类有一个额外的隐藏字段,指向外部类的实例。因此,如果 Entry 类不是静态的,那么除了具有它不需要的访问权限之外,它还会携带四个指针而不是三个。

As a rule, I would say, if you define a class that's basically there to act as a collection of data members, like a "struct" in C, consider making it static.

作为一项规则,我会说,如果您定义一个基本上用作数据成员集合的类,例如 C 中的“结构”,请考虑将其设为静态。

回答by Vinze

Simple example :

简单的例子:

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

If non-static the class cannot be instantiated exept in an instance of the upper class (so not in the example where main is a static function)

如果非静态类不能在上层类的实例中实例化(所以不是在 main 是静态函数的示例中)

回答by Leigh

There are non-obvious memory retention issues to take into account here. Since a non-static inner class maintains an implicit reference to it's 'outer' class, if an instance of the inner class is strongly referenced, then the outer instance is strongly referenced too. This can lead to some head-scratching when the outer class is not garbage collected, even though it appearsthat nothing references it.

这里需要考虑一些不明显的内存保留问题。由于非静态内部类维护对其“外部”类的隐式引用,如果内部类的实例被强引用,则外部实例也被强引用。当外部类没有被垃圾收集时,这可能会导致一些头疼,即使看起来没有任何引用它。

回答by The Gun

Non static inner classes can result in memory leaks while static inner class will protect against them. If the outer class holds considerable data, it can lower the performance of the application.

非静态内部类会导致内存泄漏,而静态内部类会防止它们发生。如果外部类拥有大量数据,则会降低应用程序的性能。

回答by John29

From http://docs.oracle.com/javase/tutorial/java/javaOO/whentouse.html:

http://docs.oracle.com/javase/tutorial/java/javaOO/whentouse.html

Use a non-static nested class (or inner class) if you require access to an enclosing instance's non-public fields and methods. Use a static nested class if you don't require this access.

如果您需要访问封闭实例的非公共字段和方法,请使用非静态嵌套类(或内部类)。如果您不需要此访问权限,请使用静态嵌套类。

回答by user1923551

static nested class is just like any other outer class, as it doesn't have access to outer class members.

静态嵌套类就像任何其他外部类一样,因为它无法访问外部类成员。

Just for packaging convenience we can club static nested classes into one outer class for readability purpose. Other than this there is no other use case of static nested class.

为了便于打包,我们可以将静态嵌套类合并到一个外部类中以提高可读性。除此之外,没有其他静态嵌套类的用例。

Example for such kind of usage, you can find in Android R.java (resources) file. Res folder of android contains layouts (containing screen designs), drawable folder (containing images used for project), values folder (which contains string constants), etc..

这种用法的示例,您可以在 Android R.java(资源)文件中找到。android 的 res 文件夹包含 layouts(包含屏幕设计)、drawable 文件夹(包含用于项目的图像)、values 文件夹(包含字符串常量)等。

Sine all the folders are part of Res folder, android tool generates a R.java (resources) file which internally contains lot of static nested classes for each of their inner folders.

由于所有文件夹都是 Res 文件夹的一部分,android 工具会生成一个 R.java(资源)文件,该文件内部包含许多用于每个内部文件夹的静态嵌套类。

Here is the look and feel of R.java file generated in android:Here they are using only for packaging convenience.

下面是在android中生成的R.java文件的外观和感觉:这里使用它们只是为了方便打包。

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}