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

Java中的静态嵌套类,为什么?,java,class,static,member,Java,Class,Static,Member,我正在查看LinkedList的Java代码,注意到它使用了一个静态嵌套类Entry public class LinkedList<E> ... { ... private static class Entry<E> { ... } } 公共类链接列表。。。{ ... 私有静态类条目{…} } 使用静态嵌套类而不是普通内部类的原因是什么 我能想到的唯一原因是,条目不能访问实例变量,所以从OOP的角度来看,它具有更好的封装性 但我想可能还有其他原因,也许是性能。

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

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

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

}
公共类链接列表。。。{
...
私有静态类条目{…}
}
使用静态嵌套类而不是普通内部类的原因是什么

我能想到的唯一原因是,条目不能访问实例变量,所以从OOP的角度来看,它具有更好的封装性

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


注意。我希望我的术语是正确的,我会称之为静态内部类,但我认为这是错误的:

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


请注意,我有偏见,因为C#fan-C#没有内部类的等价物,尽管它有嵌套类型。我不能说我已经错过了内部类:)

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


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

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


这有点像为什么我总是让我的变量在Java中成为最终变量——如果它们不是最终变量,我知道它们有一些有趣的地方。如果使用内部类而不是静态嵌套类,应该有一个很好的理由。

您链接到的Sun页面在这两者之间有一些关键区别:

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

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

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.
    }
}
不需要将
LinkedList.Entry
作为顶级类,因为它仅由
LinkedList
使用(还有一些其他接口也具有名为
Entry
的静态嵌套类,例如
Map.Entry
-相同的概念)。而且因为它不需要访问LinkedList的成员,所以它是静态的,这是一种更干净的方法


因此,我认为如果您使用的是嵌套类,最好是从它是静态的开始,然后根据您的使用情况决定它是否真的需要是非静态的。

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

作为一个规则,我会说,如果你定义了一个类,它基本上是作为数据成员的集合,比如C中的“Stutt”,考虑使它静态。

< P>简单的例子:

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

如果非静态类不能在上层类的实例中实例化exept(因此在main是静态函数的示例中不是这样)

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

非静态内部类可能会导致内存泄漏,而静态内部类将对此进行保护。如果外部类包含大量数据,则会降低应用程序的性能。

来自:

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


静态嵌套类与任何其他外部类一样,因为它无权访问外部类成员

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

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

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

以下是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;
    }
}
内阶级优势--

  • 一次性使用
  • 支持并改进封装
  • 可读性
  • 专用现场访问
  • 没有外部类的存在,内部类将不存在

    class car{
        class wheel{
    
        }
    }
    
    内部类有四种类型

  • 正规内类
  • 方法局部内部类
  • 匿名内部类
  • 静态内部类
  • 点--

  • 从静态内部类中,我们只能访问
    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() {...}
      }
    }
    
    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.
        }
    }
    
    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;
    }
    }
    
    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
    }