12

外側のクラスによって作成できる静的メンバー クラスのインスタンスの数を知りたいです。1つだけだと思いますが、ブロッホからの次の抜粋は意味がありません.

Joshua Bloch の「Effective Java」の引用 - 項目 22*: 非静的メンバー クラスよりも静的メンバー クラスを優先します。

プライベートな静的メンバー クラスの一般的な用途は、それを囲むクラスによって表されるオブジェクトのコンポーネントを表すことです。たとえば、キーを値に関連付ける Map インスタンスを考えてみましょう。多くの Map 実装には、マップ内のキーと値のペアごとに内部 Entry オブジェクトがあります。各エントリはマップに関連付けられていますが、エントリのメソッド (getKey、getValue、および setValue) はマップにアクセスする必要はありません。したがって、エントリを表すために非静的メンバー クラスを使用するのは無駄です。private 静的メンバー クラスが最適です。エントリ宣言で static 修飾子を誤って省略した場合、マップは機能しますが、各エントリにはマップへの余分な参照が含まれ、スペースと時間が無駄になります。

彼は、マップは、マップ内の各キーと値のペア、つまり静的メンバー クラスの複数のインスタンスに対して Entry オブジェクトを作成すると述べています。

だから私の仮定は間違っています!つまり、静的メンバー クラスに関する私の理解が間違っているということです。静的メンバー変数がどのように動作するかは誰もが知っています。たとえば、古典的な静的最終文字列です。オブジェクトのインスタンスは 1 つしかありません。

これは、囲んでいるオブジェクトがインスタンス化されるときに、静的メンバー クラスが実際にはインスタンス化されないことを意味しますか?

では、Entry に静的メンバー クラスを使用する Map のポイントは何でしょうか。API でインターフェイスを使用しないのはなぜですか? 他のすべての Collections クラスは、独自の実装を提供できます。

[*] 私が持っている本の PDF 版の項目 18 であることに気付きました

4

4 に答える 4

9

これは、staticキーワードのよくある誤解です。

static変数を使用すると、このクラスのすべてのオブジェクトに対してこれらのうちの 1 つだけが存在するか、またはそのようなものになることを意味します。

static Object thereWillBeOnlyOne = new Object();

ただし、内部クラスのコンテキストでは、まったく別のことを意味します。内部staticクラスは、それを取り囲むクラスのオブジェクトと接続していませんが、非静的内部クラスは接続しています。


内部staticクラス:

public class TrieMap<K extends CharSequence, V> extends AbstractMap<K, V> implements Map<K, V> {

  private static class Entry<K extends CharSequence, V> implements Map.Entry<K, V> {

私のMap.Entryクラスで使用されるTrieMapクラスは、それを作成したオブジェクトを参照する必要がないstaticため、不要な参照を保存するように作成できます。


static内部クラス:

public final class StringWalker implements Iterable<Character> {
  // The iteree
  private final String s;
  // Where to get the first character from.
  private final int start;
  // What to add to i (usually +/- 1).
  private final int step;
  // What should i be when we stop.
  private final int stop;

  // The Character iterator.
  private final class CharacterIterator implements Iterator<Character> {
    // Where I am.
    private int i;
    // The next character.
    private Character next = null;

    CharacterIterator() {
      // Start at the start.
      i = start;
    }

    public boolean hasNext() {
      if (next == null) {
        if (step > 0 ? i < stop : i > stop) {
          next = s.charAt(i);
          i += step;
        }
      }
      return next != null;
    }

オブジェクトのCharacterIterator内部は、オブジェクト内に一度だけ存在する、StringWalker反復される文字列を指します。したがって、a の反復子を多数作成でき、それらはすべて同じ文字列を処理します。sStringWalkerStringWalker


なぜこの奇妙さ?

staticこの一見非論理的な二重性は、キーワード inの使用に由来しCます。

ではC、次のことができます(または、少なくとも以前はできていました):

void doSomething () {
   static int x = 1;

   if ( x < 3 ) {
   } else {
   }
   x += 1;
}

そして、関数を呼び出すたびに、x最後に残したままになります-この場合はインクリメントされます。

概念は、変数がその囲みブロックによってスコープ的に囲まれているが、親ブロックによって意味的staticに囲まれていることをキーワードが示すというものでした。つまり、上記のコードは次とほぼ同等でした。

int x = 1;
void doSomething () {
   if ( x < 3 ) {
   } else {
   }
   x += 1;
}

ただし、関数xでのみ参照が許可されていました。

そのコンセプトを前進させるJavaと、物事はもう少し理にかなっています. static内部クラスは、クラスの外部で宣言されたのとまったく同じように動作しますが、非内部クラスは、staticそれを囲むインスタンスにより緊密に結合します。実際、インスタンスを直接参照できます。

また:

class Thing {
   static Object thereWillBeOnlyOne = new Object();

のように振る舞う

Object thereWillBeOnlyOne = new Object();
class Thing {

合法だったら。

ここでレッスンを終了します。

于 2014-07-25T10:40:10.570 に答える
2

Entry に静的メンバー クラスを使用する Map のポイントは何ですか?

これは、パッケージ構造が論理的に正しいためです。

API でインターフェイスを使用しないのはなぜですか?

さて、これは誰も巻き込みたくないデザインの議論です。

于 2014-07-25T10:21:41.987 に答える