Классы Java: анонимный против вложенного против частного - PullRequest
3 голосов
/ 29 марта 2011

Может кто-нибудь объяснить разницу между анонимными классами, вложенными классами и закрытыми классами в Java? Я хотел бы знать затраты времени выполнения, связанные с каждым из них, и подход компилятора к каждому, поэтому я могу получить представление о том, что лучше всего использовать, например. производительность (потенциал для оптимизации компилятора), использование памяти и общая приемлемость с другими Java-кодерами.

Под анонимными классами я имею в виду те, которые объявлены встроенными в функцию таким странным Java-способом. Это часто встречается в примерах кода Swing, где вы пишете обработчик кнопки, встроенный в его объявление. Мне не очень нравятся анонимные классы, потому что вы получаете эти забавные файлы MyClass $ 1.class и чаще всего вам придется реорганизовывать позже, когда выясняется, что вы хотите сделать анонимный класс синглтоном или вам нужен дескриптор или что-то. Мне также просто не нравится, как вы прикрепляете обработчик в форме чего-то, что вы только что придумали во время вызова другой функции. Это просто заставляет меня чувствовать себя странно. : -)

Частные классы - это те, которые вы пишете внизу вашего файла, полностью за пределами объявления вашего открытого класса. Я предпочитаю частные классы только потому, что они имеют смысл в других языках, где нет сильных отношений 1: 1 между исходным файлом и классом. У меня нет такого странного чувства, и я знаю (или я думаю, что знаю), как компилятор Java будет обрабатывать объявление этого класса.

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

Ответы [ 3 ]

7 голосов
/ 29 марта 2011

Может кто-нибудь объяснить разницу между анонимными классами, вложенными классами и закрытыми классами в Java?

  • Анонимные классы, например, Runnable в

    new Thread(new Runnable() {
        public void run() {
            ...
        }
    }.start();
    
  • Вложенные классы выглядят как

    class SomeClass {
    
        ...
    
        class NestedClass {
            ....
        }
    }
    
  • Закрытые классы (которые вы называете «теми, которые вы пишете внизу вашего файла полностью за пределами объявления вашего открытого класса») на самом деле являются классами с пакетной областью. Вы не можете иметь модификатор private перед классом, если он не является вложенным!

Я хотел бы знать затраты времени выполнения, связанные с каждым из них, и подход компилятора к каждому, чтобы я мог получить представление о том, что лучше всего использовать, например, для. производительность (потенциал для оптимизации компилятора), использование памяти и общая приемлемость с другими Java-кодерами.

Я сомневаюсь, что между этими подходами есть разница в производительности. Зачем? Потому что каждый подход сводится к тому, чтобы быть скомпилированным в отдельный более или менее «обычный» класс. («Более или менее» из-за того, что в некоторых случаях генерируется метод доступа, но он не имеет побочных эффектов и, скорее всего, в любом случае встроен JIT.)

Этот код:

public class TestOuter {

    int fieldOuter;
    public void methodOuter() {
    }

    class TestInner {
        int fieldInner;
        public void methodInner() {
        }
    }
}


class TestPackage {

    int fieldPackage;
    public void methodPackage() {
    }

}

Получает в виде:

$ javap -c TestOuter$TestInner
Compiled from "TestOuter.java"
public class TestOuter extends java.lang.Object{
int fieldOuter;

public TestOuter();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public void methodOuter();
  Code:
   0:   return

}

$ javap -c TestOuter
Compiled from "TestOuter.java"
public class TestOuter extends java.lang.Object{
int fieldOuter;

public TestOuter();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public void methodOuter();
  Code:
   0:   return

}

$ javap -c TestPackage
Compiled from "TestOuter.java"
class TestPackage extends java.lang.Object{
int fieldPackage;

TestPackage();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public void methodPackage();
  Code:
   0:   return

}
3 голосов
/ 29 марта 2011

Что касается стоимости во время выполнения, частные и публичные занятия одинаковы.Теоретически есть различие, потому что JVM могла бы встроить методы из частного класса проще, но это теория.

Вложенные классы: есть два вида, статические и нестатические.На самом деле это относительно большая разница: статический класс похож на закрытый класс, а нестатический класс имеет указатель (ссылка, как бы вы это ни называли) на родительский объект.Это означает, что ему нужно больше памяти, поэтому, если возможно, используйте статические вложенные классы.В противном случае вложенные классы выполняются так же быстро, как частные или публичные.Из нестатического вложенного класса вы можете получить доступ к родительскому объекту (поэтому он имеет ссылку на родительский объект), но будьте осторожны при доступе к закрытым полям, поскольку это делается с помощью специальных скрытых анонимных функций (Eclipse выдаст вам предупреждение).

Если вы действительно хотите понять все различия, вы должны использовать javap для декомпиляции класса.

1 голос
/ 29 марта 2011

Сначала исправьте терминологию.

  • A private class - это класс, который объявлен с модификатором доступа private. Этот модификатор можно использовать только для вложенного класса, поэтому частные классы являются подмножеством вложенных классов.

  • Классы, которые «вы пишете внизу вашего файла полностью вне объявления вашего открытого класса» на самом деле пакет private . И это из-за их доступа / видимости ... а не из-за того, что они находятся в одном файле с другим классом.

(Несмотря на то, что вам нравится это делать, общепринято, что это ПЛОХАЯ ИДЕЯ, чтобы поместить более одного класса верхнего уровня в один исходный файл. Для начала возможно сломать инструменты и IDE. Источник : http://geosoft.no/development/javastyle.html.)

Так в чем же разница между ними?

  • Закрытый класс пакета такой же, как обычный класс public или protected, за исключением того, что он виден ТОЛЬКО другим классам в том же пакете.

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

  • Локальный внутренний класс - это класс не static, который объявлен в другом классе. Экземпляр должен быть создан в контексте экземпляра включающего класса и иметь доступ ко всем членам этого экземпляра.

  • Анонимный внутренний класс функционально аналогичен локальному внутреннему классу, за исключением того, что:

    • оно объявлено в методе и может использовать переменные, объявленные в методах (при условии, что они final), и
    • оно и не имеет имени и не может быть создано независимо.

    Синтаксис анонимного внутреннего класса сочетает в себе объявление и создание экземпляров и предназначен для облегчения написания облегченных обратных вызовов.

А как насчет производительности?

  • Производительность вложенного класса (частного или иного) идентична обычному классу.
  • Две формы внутреннего класса имеют крошечное снижение производительности, поскольку используют скрытый атрибут, который содержит ссылку на включающий экземпляр.

А как насчет приемлемости?

  • Вложенные классы (включая частные) и две формы внутренних классов являются приемлемыми и имеют свое применение. (Очевидно, что некоторые являются более подходящими, чем другие, в зависимости от варианта использования. Но вы могли бы сказать это о каждой конструкции Java.)

  • Форма, которую вы ошибочно назвали «приватной» (где вы помещаете несколько классов верхнего уровня в один исходный файл), обычно считается плохой идеей.

...