226

I was looking at the Java code for LinkedList and noticed that it made use of a static nested class, 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.

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

4

14 に答える 14

281

リンク先のSunページには、2つの間にいくつかの重要な違いがあります。

ネストされたクラスは、それを囲むクラスのメンバーです。ネストされた非静的クラス (内部クラス) は、プライベートと宣言されている場合でも、囲んでいるクラスの他のメンバーにアクセスできます。入れ子になった静的クラスは、囲んでいるクラスの他のメンバーにアクセスできません。
...

注: 入れ子になった静的クラスは、他の最上位クラスと同様に、その外側のクラス (および他のクラス) のインスタンス メンバーと対話します。実際には、入れ子になった静的クラスは、パッケージングの便宜のために別のトップレベル クラスに入れ子になったトップレベル クラスの動作です。

によってのみ使用されるためLinkedList.Entry、最上位クラスである必要はありません(同じ概念など、名前が付けられた静的なネストされたクラスを持つ他のインターフェースもいくつかあります)。また、LinkedList のメンバーにアクセスする必要がないため、静的であることが理にかなっています。これは、はるかにクリーンなアプローチです。LinkedListEntryMap.Entry

Jon Skeet が指摘しているように、ネストされたクラスを使用している場合は、静的であることから始めて、使用法に基づいて非静的にする必要があるかどうかを判断することをお勧めします。

于 2008-10-31T13:47:43.830 に答える
48

の考えでは、内部クラスが表示されるときはいつでも、質問は逆になるはずです-インスタンスへの余分な複雑さと暗黙の(明示的で明確なIMOではなく)参照を備えた内部クラスである必要がありますか?含まれているクラスの?

注意してください、私は C# ファンとして偏見があります。C# にはネストされた型はありますが、内部クラスに相当するものはありません。私はまだ内部クラスを逃したとは言えません:)

于 2008-10-31T13:40:38.697 に答える
28

ここで考慮すべき明らかでないメモリ保持の問題があります。非静的内部クラスはその「外部」クラスへの暗黙的な参照を維持するため、内部クラスのインスタンスが強く参照されると、外部インスタンスも強く参照されます。これは、外側のクラスがガベージ コレクションされていない場合に、何も参照していないように見えても頭を悩ませる可能性があります。

于 2008-10-31T14:25:02.367 に答える
15

ビルダーパターンでは static 内部クラスを使用しています。静的内部クラスは、プライベート コンストラクターのみを持つ外部クラスをインスタンス化できます。内部クラスにアクセスする前に外部クラスのオブジェクトを作成する必要があるため、内部クラスで同じことを行うことはできません。

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.
    }
}

これは x: 1 を出力します

于 2016-10-26T16:25:59.667 に答える
11

static ネストされたクラスは、外部クラス メンバーにアクセスできないため、他の外部クラスと同じです。

パッケージ化の便宜上、静的なネストされたクラスを読みやすくするために 1 つの外部クラスにまとめることができます。これ以外に静的ネスト クラスの使用例はありません。

このような種類の使用例は、Android R.java (リソース) ファイルにあります。Android の Res フォルダーには、layouts (画面デザインを含む)、drawable フォルダー (プロジェクトで使用される画像を含む)、values フォルダー (文字列定数を含む) などが含まれます。

すべてのフォルダーが Res フォルダーの一部であるため、Android ツールは、内部フォルダーごとに多くの静的なネストされたクラスを内部的に含む R.java (リソース) ファイルを生成します。

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;
    }
}
于 2013-12-16T10:31:19.713 に答える
10

一つには、非静的内部クラスには、外部クラスのインスタンスを指す追加の非表示フィールドがあります。したがって、Entryクラスが静的でない場合、必要のないアクセス権があることに加えて、3つではなく4つのポインターを運ぶことになります。

原則として、Cの「構造体」のように、データメンバーのコレクションとして機能するために基本的にそこにあるクラスを定義する場合は、静的にすることを検討してください。

于 2008-10-31T13:52:51.667 に答える
6

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

外側のインスタンスの非パブリック フィールドおよびメソッドへのアクセスが必要な場合は、非静的ネスト クラス (または内部クラス) を使用します。このアクセスが必要ない場合は、ネストされた静的クラスを使用してください。

于 2013-11-21T19:09:03.753 に答える
4

簡単な例:

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

非静的の場合、上位クラスのインスタンスを除いてクラスをインスタンス化できません(したがって、mainが静的関数である例ではインスタンス化できません)。

于 2008-10-31T13:58:25.587 に答える
2

静的と通常の理由の 1 つは、クラスローディングに関係しています。親のコンストラクターで内部クラスをインスタンス化することはできません。

PS: 私は常に「入れ子」と「内部」が交換可能であることを理解していました。用語には微妙なニュアンスがあるかもしれませんが、ほとんどの Java 開発者はどちらも理解できます。

于 2008-10-31T13:46:06.737 に答える
0

パフォーマンスの違いについてはわかりませんが、あなたが言うように、静的なネストされたクラスは、囲んでいるクラスのインスタンスの一部ではありません。本当に内部クラスにする必要がない限り、静的なネストされたクラスを作成する方が簡単なようです。

これは、Java で変数を常に final にする理由と少し似ています。ネストされた静的クラスの代わりに内部クラスを使用する場合は、正当な理由があるはずです。

于 2008-10-31T13:46:27.700 に答える
-1

内部クラスの利点 --

  1. 1回の使用
  2. カプセル化のサポートと改善
  3. 可読性
  4. プライベート フィールド アクセス

外部クラスが存在しなければ、内部クラスは存在しません。

class car{
    class wheel{

    }
}

内部クラスには 4 つのタイプがあります。

  1. 通常の内部クラス
  2. メソッド ローカル 内部クラス
  3. 匿名の内部クラス
  4. 静的内部クラス

点 - -

  1. 静的内部クラスからは、外部クラスの静的メンバーにのみアクセスできます。
  2. 内部クラス内では static member を宣言できません。
  3. 外部クラスの静的領域で通常の内部クラスを呼び出すため。

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

  4. 外部クラスのインスタンス領域で通常の内部クラスを呼び出すため。

    Inner i=new Inner();

  5. 外部クラスの外側で通常の内部クラスを呼び出すため。

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

  6. inside 内部クラス 内部クラスへのポインタ。

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

  7. 内部クラスの適用可能な修飾子は -- public,default,

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

  8. outer$inner は内部クラス名の名前です。

  9. インスタンスメソッド内の内部クラスでは、外部クラスの静的およびインスタンスフィールドにアクセスできます。

10.静的メソッド内の内部クラスの場合、静的フィールドのみにアクセスできます

外側のクラス。

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
            }
        }
    }
}
于 2016-03-01T07:10:09.810 に答える