Java中常用内部类吗?他们“坏”吗?

时间:2009-06-22 18:58:26

标签: java inner-classes

Java中常用的内部类是什么?这些是否与嵌套类相同?或者用Java更换这些更好的东西?我有一本关于第5版的书,它有一个使用内部类的例子,但我想我读过一些内部类是“糟糕的”。

我不知道并且希望对此有所了解。

谢谢。

8 个答案:

答案 0 :(得分:30)

经常使用内部类,并且非常相似的东西 - 匿名类 - 实际上是不可或缺的,因为它们是Java最接近闭包的东西。所以,如果你不记得你在哪里听到内心阶级是坏的,那就试着忘记吧!

答案 1 :(得分:19)

他们并非“坏”。

他们可能会受到滥用(例如内部类的内部类)。一旦我的内部类跨越了几行,我宁愿将它提取到自己的类中。它有助于提高可读性,并在某些情况下进行测试。

有一个问题不是很明显,值得记住。任何非static内部类都将对周围的外部类(隐式的“this”引用)进行隐式引用。这通常不是问题,但是如果你来序列化内部类(比如说,使用XStream),你会发现这会导致你意想不到的悲伤。

答案 2 :(得分:4)

我不认为他们是邪恶的。也许它们没有被广泛使用,但它们确实有很多用途,回调就是其中之一。一个特殊的优点是它们可以从与外部类不同的类扩展,因此您可以拥有多个继承。

我想说内部类的一个问题是它们的语法有点“难看”。这是让一些人望而却步的东西。在这里工作的有很多。

答案 3 :(得分:2)

内部类的一个很好的例子是给定集合类型的迭代器实现。它是一个实现公共接口的类,但除了与另一个类关联之外没有任何业务存在。它允许您使用友元操作符对C ++中您将被强制执行的操作进行建模。

答案 4 :(得分:2)

非静态内部类可以隐藏性能问题。他们可以访问封闭类的成员字段,但不能直接访问,而是通过自动创建的getter访问。这比将封闭类的成员复制到内部类更慢。

描述了非静态内部类的一些其他问题here

答案 5 :(得分:1)

它们很有用,可以非常常用。虽然你应该对滥用功能持谨慎态度,但它们不会比任何其他语言功能更容易被滥用。

答案 6 :(得分:0)

要记住的关键是你要通过使两个类更紧密耦合来交换灵活性以实现简单性和凝聚力。您可能希望这些类紧密绑定,但是您放弃了通过不从包含类之外的接口定义类来透明地将其他类交换到当前嵌入类的位置的能力。

答案 7 :(得分:0)

请考虑以下示例:

public class OuterClass {

private AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass() {
    @Override
    protected void printAboutme() {
        System.out.println("AnonymousInnerClass.printAboutMe.........");
        Class clazz = this.getClass();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {

            String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
            message = message + " " + field.getType().getSimpleName();
            message = message + " " + field.getName();

            System.out.println(message);
        }
    }
};

public void displayAnonymousInnerClass() {
    anonymousInnerClass.printAboutme();
}

public void displayStaticInnerClass() {
    NestedStaticClass staticInnerClass = new NestedStaticClass();
    staticInnerClass.printAboutMe();
}

public void displayInnerClass() {
    InnerClass innerClass = new InnerClass();
    innerClass.printAboutMe();
}

public void displayMethodInnerClass(){

    class MethodInnerClass {

        private String sampleField = "Method Inner Class";
        public void printAboutMe() {
            System.out.println("MethodInnerClass.printAboutMe.........");
            Class clazz = this.getClass();

            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {

                String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
                message = message + " " + field.getType().getSimpleName();
                message = message + " " + field.getName();

                System.out.println(message);
            }
        }
    }

    MethodInnerClass methodInnerClass = new MethodInnerClass();
    methodInnerClass.printAboutMe();
}

class InnerClass {
    private String sampleField = "Inner Class";
    public void printAboutMe() {
        System.out.println("InnerClass.printAboutMe.........");
        Class clazz = this.getClass();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {

            String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
            message = message + " " + field.getType().getSimpleName();
            message = message + " " + field.getName();

            System.out.println(message);
        }
    }
}


abstract class AnonymousInnerClass {
    protected String sampleField = "Anonymous Inner Class";
    protected abstract void printAboutme();
}

static class NestedStaticClass {
    private String sampleField = "NestedStaticClass";
    public void printAboutMe() {
        System.out.println("NestedStaticClass.printAboutMe.........");
        Class clazz = this.getClass();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {

            String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
            message = message + " " + field.getType().getSimpleName();
            message = message + " " + field.getName();

            System.out.println(message);
        }
    }
}

}

在这个例子中,每种类型的非静态嵌套类与静态嵌套类进行比较。现在,如果为每个嵌套类运行外部类的显示方法,您将看到每个嵌套类printAboutMe()方法的输出,一些反射代码,用于打印嵌套类的所有成员变量。

对于非嵌套类,您将看到在代码中除了声明的变量字符串之外还有一个额外的成员变量,它仅在运行时出现。

例如,如果我们为InnerClass执行以下代码。 : -

public class NestedClassesDemo {

public static void main(String[] args) {
    OuterClass outerClass = new OuterClass();
    outerClass.displayInnerClass();
}

}

输出是这样的: -

InnerClass.printAboutMe.........
private String sampleField
protected OuterClass this$0

注意有一个神秘的成员变量,这个类型为封闭类(外类)的$ 0。

现在您已经清楚内部类继续引用外部类。所以您将内部类的引用传递给其他外部世界类然后引用永远不会被释放到OuterClass也被引用,因此泄漏。

因此,如果不使用内部类,这会使内部类变坏。

静态内部类没有这种情况。请运行所有显示方法。如果代码中有任何问题请指出。