简体   繁体   English

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

[英]Static nested class in Java, why?

I was looking at the Java code for LinkedList and noticed that it made use of a static nested class, Entry .我正在查看LinkedList的 Java 代码,并注意到它使用了一个静态嵌套类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

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.Entry to be top-level class as it is only used by LinkedList (there are some other interfaces that also have static nested classes named Entry , such as Map.Entry - same concept).有没有必要LinkedList.Entry是顶层类,因为它只是使用LinkedList (还有一些其他的界面,也有静态的嵌套类名为Entry ,如Map.Entry -同一概念)。 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 的成员,所以它是静态的 - 这是一种更简洁的方法。

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

To my mind, the question ought to be the other way round whenever you see an inner class - does it really need 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.请注意,我偏向于 C# 粉丝 - C# 没有等效的内部类,尽管它确实具有嵌套类型。 I can't say I've missed inner classes yet :)我不能说我已经错过了内部课程:)

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 appears that nothing references it.当外部类没有被垃圾收集时,这可能会导致一些头疼,即使看起来没有任何引用它。

Static inner class is used in the builder pattern.静态内部类用于构建器模式。 Static inner class can instantiate it's outer class which has only private constructor.静态内部类可以实例化它的外部类,它只有私有构造函数。 You can not do the same with the inner class as you need to have object of the outer class created prior to accessing the inner class.你不能对内部类做同样的事情,因为你需要在访问内部类之前创建外部类的对象。

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }
    
    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

This will output x: 1这将输出 x: 1

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.这种用法的示例,您可以在 Android R.java(资源)文件中找到。 Res folder of android contains layouts (containing screen designs), drawable folder (containing images used for project), values folder (which contains string constants), etc.. 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;
    }
}

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 中的“结构”,请考虑将其设为静态。

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.如果您不需要此访问权限,请使用静态嵌套类。

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 是静态函数的示例中)

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. PS:我一直认为“嵌套”和“内部”是可以互换的。 There may be subtle nuances in the terms but most Java developers would understand either.术语中可能存在细微差别,但大多数 Java 开发人员都可以理解。

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.如果外部类拥有大量数据,则会降低应用程序的性能。

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.这有点像为什么我总是在 Java 中将我的变量设为 final - 如果它们不是 final,我知道它们会发生一些有趣的事情。 If you use an inner class instead of a static nested class, there should be a good reason.如果您使用内部类而不是静态嵌套类,则应该有充分的理由。

Using a static nested class rather than non-static one may save spaces in some cases.在某些情况下,使用静态嵌套类而不是非静态类可能会节省空间。 For example: implementing a Comparator inside a class, say Student.例如:在一个类中实现一个Comparator ,比如 Student。

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

Then the static ensures that the Student class has only one Comparator, rather than instantiate a new one every time a new student instance is created.然后static确保 Student 类只有一个 Comparator,而不是每次创建新的学生实例时实例化一个新的。

  1. JVM knows no nested classes. JVM 不知道嵌套类。 Nesting is just syntactic sugar.嵌套只是语法糖。

    Below images shows Java file:下图显示了 Java 文件:

    在此处输入图片说明

    Below images show class files representation of the java file :下图显示了 java 文件的类文件表示:

    在此处输入图片说明

    Notice that 2 class files are generated, one for parent and another for nested class.请注意,生成了 2 个类文件,一个用于父类,另一个用于嵌套类。

  2. Non-static nested class' objects have access to the enclosing scope.非静态嵌套类的对象可以访问封闭范围。 That access to the enclosing scope is maintained by holding an implicit reference of the enclosing scope object in the nested object通过在嵌套对象中保存对封闭范围对象的隐式引用来维护对封闭范围的访问

  3. Nested class is a way to represent the intent that the nested class type represents a component of the parent class.嵌套类是一种表示嵌套类类型表示父类的组件的意图的方式。

     public class Message { private MessageType messageType; // component of parent class public enum MessageType { SENT, RECEIVE; } } class Otherclass { public boolean isSent(Message message) { if (message.getMessageType() == MessageType.SENT) { // accessible at other places as well return true; } return false; } }
  4. private static nested class represents Point#3 & the fact the nested type can only be the subcomponent to the parent class.私有静态嵌套类表示 Point#3 & 事实上嵌套类型只能是父类的子组件。 It can't be used separately.不能单独使用。

     public class Message { private Content content; // Component of message class private static class Content { // can only be a component of message class private String body; private int sentBy; public String getBody() { return body; } public int getSentBy() { return sentBy; } } } class Message2 { private Message.Content content; // Not possible }
  5. More details here .更多细节在这里

Adavantage of inner class--内部类的优势--

  1. one time use一次使用
  2. supports and improves encapsulation支持和改进封装
  3. readibility可读性
  4. private field access私人现场访问

Without existing of outer class inner class will not exist.没有外部类的存在,内部类就不会存在。

class car{
    class wheel{

    }
}

There are four types of inner class.内部类有四种类型。

  1. normal inner class普通内部类
  2. Method Local Inner class方法本地内部类
  3. Anonymous inner class匿名内部类
  4. static inner class静态内部类

point ---观点 - -

  1. from static inner class ,we can only access static member of outer class.从静态内部类,我们只能访问外部类的静态成员。
  2. Inside inner class we cananot declare static member .在内部类中,我们不能声明静态成员。
  3. inorder to invoke normal inner class in static area of outer class.为了在外部类的静态区域调用正常的内部类。

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  4. inorder to invoke normal inner class in instance area of outer class.为了在外部类的实例区域调用普通的内部类。

    Inner i=new Inner();

  5. inorder to invoke normal inner class in outside of outer class.为了在外部类之外调用正常的内部类。

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  6. inside Inner class This pointer to inner class. inside 内部类 这个指向内部类的指针。

    this.member-current inner class outerclassname.this--outer class

  7. for inner class applicable modifier is -- public,default,对于内部类适用的修饰符是 -- public,default,

    final,abstract,strictfp,+private,protected,static

  8. outer$inner is the name of inner class name. external$inner 是内部类名的名称。

  9. inner class inside instance method then we can acess static and instance field of outer class.实例方法内部的内部类然后我们可以访问外部类的静态和实例字段。

10.inner class inside static method then we can access only static field of 10.inner类里面的静态方法那么我们只能访问静态字段

outer class.外班。

class outer{

    int x=10;
    static int y-20;

    public void m1() {
        int i=30;
        final j=40;

        class inner{

            public void m2() {
                // have accees x,y and j
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM