有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

oop Bloch高效的Java更喜欢静态类而不是非静态类有多少实例?

我想知道封闭类可以创建多少个静态成员类实例。我假设只有一个,但是下面从布洛赫那里摘录的内容对我来说没有意义

引用Joshua Bloch的有效Java-Item 22*:喜欢静态成员类而不是非静态成员类

A common use of private static member classes is to represent components of the object represented by their enclosing class. For example, consider a Map instance, which associates keys with values. Many Map implementations have an internal Entry object for each key-value pair in the map. While each entry is associated with a map, the methods on an entry (getKey, getValue and setValue) do not need access to the map. Therefore, it would be wasteful to use a nonstatic member class to represent entries: a private static member class is best. If you accidentally omit the static modifier in the entry declaration, the map will still work, but each entry will contain a superfluous reference to the map, which wastes space and time.

他指出,映射为映射中的每个键值对创建一个条目对象,即静态成员类的多个实例

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

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

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

[*]刚刚意识到这是我所拥有的PDF版本书中的第18项


共 (4) 个答案

  1. # 1 楼答案

    what's the point of Map using a static member class for Entry?

    这是因为,它使包结构在逻辑上正确

    Why not just use an interface on the API?

    现在,这是一个没有人愿意卷入的设计讨论

  2. # 2 楼答案

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

    当您将static与一个变量一起使用时,它意味着这个类的所有对象都只有一个变量

    static Object thereWillBeOnlyOne = new Object();
    

    然而,在内部类的上下文中,它意味着完全不同的东西Astatic内部类与封闭类的对象没有连接,而非静态内部类与封闭类的对象没有连接


    一个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> {
    

    我的TrieMap类使用的Map.Entry类不需要引用创建它的对象,因此可以使它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;
        }
    

    StringWalker对象内的CharacterIterator引用要迭代为s的字符串,该字符串在StringWalker对象中只存在一次。因此,我可以创建一个StringWalker的许多迭代器,它们都在相同的字符串中运行


    为什么会这样奇怪

    这种看似不合逻辑的二元性源于在C中使用static关键字

    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只允许在函数内部被引用

    把这个概念带到{}中去,现在事情变得更有意义了。static内部类的行为与在类外部声明的行为完全相同,而非static内部类与其封闭实例的结合更紧密——事实上,它可以直接引用实例

    此外:

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

    表现得很像

    Object thereWillBeOnlyOne = new Object();
    class Thing {
    

    如果合法的话

    这节课到此结束

  3. # 3 楼答案

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

    Map的情况下,之所以选择它,完全是因为名称Map.Entry表明EntryMap相关。正如您所建议的,仅使用普通类进行此操作是完全合理的。唯一的区别是你不能写Map.Entry

    我认为他们应该做的是为静态嵌套类使用“非静态”内部类(即封闭类中的class)的语法,而不是发明一个新的关键字来创建“非静态”内部类,因为这些类的行为不同于普通类。可能是attached class之类的。当然,选择关键字static是为了避免保留太多的关键字,但我认为这只会造成混乱

  4. # 4 楼答案

    是的,无论嵌套类是静态的,您都可以拥有嵌套类的多个实例

    当嵌套类是静态的时,您可以创建它的实例,而不需要封闭类的实例,这是好处之一,基本上是静态和非静态嵌套类之间的主要区别

    Does this mean then that a static member class is not actually instantiated when the enclosing object is instantiated?

    当它的构造函数被调用时,它被实例化。与非静态类没有任何区别。当代码第一次访问嵌套类时,它本身由JVM加载。我认为,与其他类相比,这也没有什么不同(虽然不是100%确定,但您可以自己测试)。所以我认为您混合了“通过JVM加载类”和“实例化类”这两个术语

    Well in that case, what's the point of Map using a static member class for Entry? Why not just use an interface on the API?

    如上所述,创建静态嵌套类的实例更容易。您不需要一个封闭的实例,它有时(可能大多数时候)正是您想要的

    另见:

    (1) Nested Classes

    (2) How can the JVM decide if a class is nested into another class?

    (3) Loading of a nested class by the JVM

    您可以沿着这些行搜索其他引用
    参考文献(2)似乎是先进的,与你的问题无关