实例化内部类

56

我正在处理一个覆盖hashCode和equals方法的示例问题,但出现了错误:"No enclosing instance of type CustomHashCodeExample is accessible. Must qualify the allocation with an enclosing instance of type CustomHashCodeExample (e.g. x.new A() where x is an instance of CustomHashCodeExample)." 我编写了一个内部类HashPerson,在另一个名为testHashCodeOverride()的方法中尝试实例化这个内部类时,出现了这个错误。

public static void testHashCodeOverride(){   
    System.out.println("\nTest HashCode Override Method");
    System.out.println("==================================\n");

    HashPerson william = new HashPerson("willy");
    HashPerson bill = new HashPerson("willy");          
}

这段代码运行良好,尽管我没有看到静态内部类或者外部类的实例化,感到困惑 :(

public class HashCodeExample {

    public static void testHashCodeOverride() {

        HashPerson william = new HashPerson("Willy");
        HashPerson bill = new HashPerson("Willy");
        System.out.println("Hash code for william  = " + william.hashCode());
        System.out.println("Hash code for bill     = " + bill.hashCode());

        HashMap table = new HashMap();
        table.put(william, "Silly");

        if (table.containsKey(william)) {
            System.out.println(table.get(william));
        } else {
            System.out.println("Key " + william + " not found");
        }

        if (table.containsKey(bill)) {
            System.out.println(table.get(bill));
        } else {
            System.out.println("Key " + bill + " not found");
        }


    }

    class HashPerson {
        private static final int HASH_PRIME = 1000003;

        public HashPerson(String name) {
            this.name = name;
        }

        public String toString() {
            return name;
        }

        public boolean equals(Object rhs) {
            if (this == rhs)
                return true;

            // make sure they are the same class
            if (rhs == null || rhs.getClass() != getClass())
                return false;

            // ok, they are the same class. Cast rhs to HashPerson
            HashPerson other = (HashPerson) rhs;

            // our test for equality simply checks the name field
            if (!name.equals(other.name)) {
                return false;
            }

            // if we get this far, they are equal
            return true;
        }
        public int hashCode() {
            int result = 0;
            result = HASH_PRIME * result + name.hashCode();
            return result;
        }
        private String name;

    }
}

您可以将您的 hashCode 方法简化为 return name.hashCode(); - Steve Kuo
@Jonik:感谢您清理代码格式。我还没有足够的声望来做到这一点。不过这让我有点困惑。当我查看代码时,它应该产生相同的“没有封闭实例”错误,因为静态方法testHashCodeOverride想要实例化一个非静态嵌套(=内部)类HashPerson的对象。 - MForster
@Steve,这是一个示例,展示了如何覆盖所有情况下的哈希码,我只是在尝试自己做同样的事情。name.hashCode(); 会返回内存地址,对吗? - t0mcat
@t3ch name.hashCode() 返回 name 的哈希码。由于 name 是一个字符串,因此哈希基于字符串的文本。 - Steve Kuo
可能是重复的问题:Java - No enclosing instance of type Foo is accessible - fabian
显示剩余2条评论
3个回答

150

我认为你想将 HashPerson 类声明为 static。否则,它只能在包含类的上下文中实例化,例如在包含类的方法中或使用如下代码:

ContainingClass container = new ContainingClass();
HashPerson william = container.new HashPerson("willy");

实际上,我的经验法则是将任何嵌套的类都声明为静态的,除非我有特殊的原因不这样做。这也更加高效,因为非静态嵌套类(称为内部类)总是包含对包含对象的隐式引用。


谢谢MForster,我感到困惑的地方是,我有一个示例程序,它的编写方式与我在这里所做的完全相同,在那个代码中,内部类不是静态的,也没有创建包含类的实例。我在那段代码中漏掉了什么吗?“在我的问题中附上代码” - t0mcat
他们是在包含类的方法中创建实例吗? - MForster
因为非静态嵌套类(称为内部类)始终包含对包含对象的隐式引用。MForster,为什么内部类引用包含类是不好的? - t0mcat
内部类是我个人认为在非单例中处理单例依赖注入的好方法。您可以使用单例工厂类来创建具有接口的内部类(通常不会使用构造函数),其中包含单例依赖关系,而无需使用构造函数。另一种用途是包装所有使用相同参数的私有方法,以再次减少混乱。例如表示循环或序列中迭代的类,您真的想要为某些具有有限范围的私有类传递构造函数的东西吗? - Novaterata
@Novaterata,你说的是对的。它属于我上面所说的例外情况(“除非我有特殊原因不这样做”)。但它也不适用于问题中的代码。 - MForster
显示剩余2条评论

10

你需要把内部类声明为静态的,或者通过外部类的实例引用它。很可能你只是想将内部类声明为静态的。

类的非静态成员(变量、方法、内部类)是与该类的每个实例相关联的。因此,在静态上下文(例如像testHashCodeOverride这样的静态方法)中访问非静态成员时,你需要指定一个封闭类的实例。


嗨,oksayt,那么在大多数情况下,我们应该将内部类设置为静态的吗?哪种方式更好?通过外部类的实例访问还是静态的? - t0mcat
不要在公共API中使用内部类。内部类是为了具有闭包和匿名类而添加的。 - Aaron Digulla
默认情况下,顶层类是静态的,但内部类是非静态的。如果您只是为了代码组织目的而创建内部类,则最好将其设置为“静态”,并像独立类一样处理它(具有限制可见性的选项)。如果您需要内部类访问其封闭类的非静态成员,则应将其设置为非静态。 - oksayt

2

我看到有不同的可能性来实例化内部类。

  1. Static Inner Class : When Inner class is static, let say code looks like as describe.

    class OuterClass 
    {
        static int outer_x = 10;
        int outer_y = 20;
        // static nested class 
        static class StaticNestedClass {
            void display() {
    
            }
        }
    }
    
    OuterClass.StaticNestedClass nestedObject =
     new OuterClass.StaticNestedClass();
    
或者仅对于静态类,这就足够了。
 new StaticNestedClass();
  1. Local inner Classes (Non Static) : Inner Classes which are not static, one good thing with local inner classes that they can access all private data members of enclosed class.

    OuterClass outerObject = new OuterClass(); 
    OuterClass.InnerClass innerObject = outerObject.new InnerClass();
    
  2. Anonymous Inner Class (implementing Interface) : This type of classes generally hidden, One can't directly see the Class{...} block in code , That is why known as Anonymous Inner Class. Here describes how to instantiate it in case inner class implementing an interface Runnable Interface.

    Runnable r = new Runnable() 
    { 
      //This is Anonymous Class
      public void run() {
        System.out.println("Child Thread");
      }
    };
    
  3. Anonymous Inner Class (Extending One Class):We can have an anonymous inner class that extends a class, Here i am taking example of Thread Class,

    Thread t = new Thread(new Runnable() 
    {
      //Anonymous Inner class
    public void run() {
        System.out.println("Child Thread");
    }
    });
    
  4. Anonymous Inner class that defines inside method/constructor argument : Inner Classes could be define within methods as well, here giving example how can we define and instantiate it within argument

    public static void main(String[] args) 
    { 
    //Here we are using Anonymous Inner class 
    //that define inside argument, here constructor argument 
    Thread t = new Thread(new Runnable() 
    { 
        public void run() 
        { 
            System.out.println("Child Thread"); 
        } 
    });
    t.start();
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接