Подтвердить что ты не робот

Внутренние классы обычно используются в Java? Они "плохие"?

Являются ли внутренние классы, обычно используемые в Java? Являются ли они такими же, как вложенные классы? Или они были заменены на Java чем-то лучше? У меня есть книга на версии 5, и у нее есть пример с использованием внутреннего класса, но я думал, что я читал, что внутренние классы были "плохими".

Я понятия не имею и надеялся на мысли о нем.

Спасибо.

4b9b3361

Ответ 1

Часто используются внутренние классы, и что-то очень похожее - анонимные классы - практически незаменимы, так как они являются наиболее близкими к тому, что Java закрывает. Поэтому, если вы не можете вспомнить, где вы слышали, что внутренние классы плохие, постарайтесь забыть об этом!

Ответ 2

Они не "плохие" как таковые.

Они могут подвергаться злоупотреблениям (например, внутренние классы внутренних классов). Как только мой внутренний класс охватывает более нескольких строк, я предпочитаю извлекать его в свой класс. Это помогает читать и тестировать в некоторых случаях.

Там есть один, который не сразу очевиден, и стоит вспомнить. Любой внутренний класс не static будет иметь неявную ссылку на окружающий внешний класс (неявная "эта" ссылка). Обычно это не проблема, но если вы приступите к сериализации внутреннего класса (скажем, используя XStream), вы обнаружите, что это может вызвать неожиданное горе.

Ответ 3

Я не думаю, что они злые или плохие. Возможно, они не широко используются, но у них есть много применений, обратные вызовы являются одним из них. Особым преимуществом является то, что они могут простираться от другого класса, чем внешний класс, поэтому вы можете иметь множественное наследование.

Я бы сказал, что одна из проблем с внутренними классами состоит в том, что их синтаксис несколько "уродлив". Это то, что отговаривает некоторых людей. Здесь на работе их много.

Ответ 4

Хорошим примером внутреннего класса является реализация итератора для данного типа коллекции. Его класс, который реализует публичный интерфейс, но не имеет существующего бизнеса, кроме как в связи с другим классом. Он позволяет моделировать вещи, которые на С++ вы должны были бы сделать с оператором друга.

Ответ 5

Нестатические внутренние классы могут скрыть проблему производительности. Они имеют доступ к полям-членам в охватывающем классе, но не напрямую, а через получатели, которые создаются автоматически. Это будет медленнее, чем просто копирование членов охватывающего класса во внутренний класс.

Некоторые другие проблемы с нестационарными внутренними классами описаны здесь

Ответ 6

Они полезны и могут быть очень широко использованы. Хотя вы должны быть осторожны в злоупотреблении функциональностью, они не могут более подвергать насилию, чем любые другие языковые функции.

Ответ 7

Главное, что нужно помнить, это то, что вы собираетесь торговать гибкостью для простоты и сплоченности, делая эти два класса более тесно связанными. Вы можете захотеть, чтобы классы были жестко привязаны, но вы отказываетесь от возможности прозрачной замены других классов на место того, что в настоящее время является вашим внедренным классом, не определяя ваш класс из интерфейса за пределами содержащего класса.

Ответ 8

Рассмотрим следующий пример:

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 для каждого вложенного класса, вы увидите вывод каждого метода printstable() вложенного класса, который имеет некоторый код отражения для печати всех переменных-членов вложенных классов.

Вы увидите, что для не вложенных классов есть одна дополнительная переменная-член, отличная от объявленной строки переменной в коде, которая присутствует только во время выполнения.

например, если мы выполним следующий код для 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

Обратите внимание, что существует переменная-член mystery this $0 типа охватывающего класса (класс Outer).

Теперь вы поняли, что внутренние классы сохраняют ссылку на внешний класс. Сценарий изображения, в котором вы передаете ссылку внутреннего класса на другой внешний мир, а затем ссылка никогда не будет выпущена, в свою очередь, OuterClass также ссылается, следовательно, на утечку.

Таким образом, это делает использование внутренних классов плохим, если не используется prpperly.

Там нет такого случая со статическими внутренними классами. Пожалуйста, запустите все методы отображения. Также, если какая-либо проблема в коде, пожалуйста, укажите.