Bloch Effective Java - 支持非静态的静态类 - 有多少个实例?

Ada*_*dam 10 java oop nested-class static-class

我想知道封闭类可以创建多少个静态成员类的实例.我只假设一个,但是Bloch的以下摘录对我来说没有意义.

引用Joshua Bloch的有效Java - 项目22*:支持非静态的静态成员类.

私有静态成员类的常见用法是表示由其封闭类表示的对象的组件.例如,考虑一个Map键,它将键与值相关联.许多Map实现都为地图中的每个键值对都有一个内部Entry对象.虽然每个条目都与一个映射关联,但条目上的方法(getKey,getValue和setValue)不需要访问映射.因此,使用非静态成员类来表示条目是浪费的:私有静态成员类是最好的.如果您不小心在条目声明中省略了静态修饰符,则地图仍然有效,但每个条目都将包含对地图的多余引用,这会浪费空间和时间.

他声明地图为地图中的每个键值对创建了一个Entry对象,即静态成员类的多个实例.

所以我的假设是错误的!这意味着我对静态成员类的理解是错误的.每个人都知道静态成员变量的行为方式,例如经典的静态最终字符串 - 只有一个对象的实例.

这是否意味着当实例化封闭对象时,实际上没有实例化静态成员类?

那么在这种情况下,使用静态成员类进行Entry的Map有什么意义呢?为什么不在API上使用接口?然后,每个其他Collections类都可以提供它自己的实现.

[*]刚才意识到它是我所拥有的PDF版本的第18项

Old*_*eon 8

这是对static关键字的常见误解.

当你使用static变量时,意味着这个类的所有对象或类似的东西中只有一个.

static Object thereWillBeOnlyOne = new Object();
Run Code Online (Sandbox Code Playgroud)

然而,在内部类的上下文中,它意味着完全不同的东西.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> {
Run Code Online (Sandbox Code Playgroud)

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;
    }
Run Code Online (Sandbox Code Playgroud)

CharacterIterator一个内部StringWalker对象指的是字符串进行迭代为s仅在存在一次StringWalker对象.因此,我可以创建一个a的迭代器,StringWalker它们都是相同的字符串.


为什么这么古怪?

这种看似不合逻辑的二元性来自于使用static关键字C.

C你可以(或至少曾经能够)做:

void doSomething () {
   static int x = 1;

   if ( x < 3 ) {
   } else {
   }
   x += 1;
}
Run Code Online (Sandbox Code Playgroud)

并且每次调用该函数时,x都会像上次离开时​​一样 - 在这种情况下递增.

概念是static关键字表明变量被其封闭块大量包围,但在语义上由其父块包围.即上面的代码大致相当于:

int x = 1;
void doSomething () {
   if ( x < 3 ) {
   } else {
   }
   x += 1;
}
Run Code Online (Sandbox Code Playgroud)

x只允许在函数引用.

把这个概念推进到Java现在,事情变得更有意义.一个static内部类的行为完全就像是声明的类外,同时非static内债券更紧密其外围实例-事实上,它可以直接引用的实例.

也:

class Thing {
   static Object thereWillBeOnlyOne = new Object();
Run Code Online (Sandbox Code Playgroud)

表现得很像

Object thereWillBeOnlyOne = new Object();
class Thing {
Run Code Online (Sandbox Code Playgroud)

如果它是合法的.

这里吸取了教训.


Enn*_*oji 5

我认为 Java 团队搞砸了这个命名。静态内部类(严格来说,它们的正确名称是“静态嵌套类”)与普通类没有任何区别,只是它有一个奇特的名称(Something.MyClass而不是MyClass)并且可以设为私有(即不能从其他类实例化)。

就 而言Map,选择它只是因为名称Map.Entry清楚地表明与Entry相关Map。正如您所建议的,为此使用普通类是完全合理的。唯一的区别是你不用写Map.Entry

我认为他们应该做的是对静态嵌套类使用“非静态”内部类(即仅class在封闭类中)的语法,而不是发明一个新关键字来创建“非静态”内部类,因为这些类的行为与普通类不同。也许类似的东西attached class。据我所知,选择关键字static是为了避免有太多保留关键字,但我认为这只会加剧混乱。