27

Java中常用内部类吗?这些与嵌套类相同吗?还是这些在 Java 中被更好的东西取代了?我有一本关于版本 5 的书,它有一个使用内部类的示例,但我认为我读到过一些内部类是“坏的”。

我不知道,并希望对此有想法。

谢谢你。

4

8 回答 8

34

内部类经常被使用,并且非常相似的东西——匿名类——实际上是必不可少的,因为它们是 Java 最接近闭包的东西。因此,如果您不记得在哪里听说过内​​部类不好,请尝试忘记它!

于 2009-06-22T19:02:31.690 回答
22

它们本身并不“坏”。

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

有一个问题不是很明显,但值得记住。任何非static内部类都会隐式引用周围的外部类(隐式“this”引用)。这通常不是问题,但是如果您对内部类进行序列化(例如,使用XStream),您会发现这可能会给您带来意想不到的痛苦。

于 2009-06-22T19:06:47.437 回答
4

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

我会说内部类的问题之一是它们的语法有点“丑陋”。这让一些人感到沮丧。在工作中有很多人。

于 2009-06-22T19:03:20.940 回答
2

内部类的一个很好的例子是给定集合类型的迭代器实现。它是一个实现公共接口的类,但除了与另一个类关联外,没有业务存在。它允许您对在 C++ 中您将被迫使用朋友运算符进行的事情进行建模。

于 2009-06-22T20:05:33.327 回答
2

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

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

于 2009-06-22T20:51:55.760 回答
1

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

于 2014-03-12T17:49:38.693 回答
1

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

于 2009-06-22T19:08:26.967 回答
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);
        }
    }
}

}

在此示例中,将每种类型的非静态嵌套类与静态嵌套类进行了比较。现在,如果您为每个嵌套类运行 Outer 类的显示方法,您将看到每个嵌套类 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

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

现在您很清楚内部类保持对外部类的引用。因此,图像场景中,您将内部类的引用传递给其他外部世界类,然后引用永远不会被释放到反过来 OuterClass 也被引用,因此泄漏。

因此,如果不正确使用,这会使使用内部类变得很糟糕。

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

于 2016-02-03T02:03:15.493 回答