Вопрос по java – Головоломка видимости внутреннего класса Java

10

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

public class A {
  public A() { b = new B(); }
  B b;
  private class B { }
}

Из предупреждения в Eclipse я цитирую следующее: компилятор java эмулирует конструктор A.B () с помощью синтетического метода доступа. Я предполагаю, что компилятор теперь идет вперед и создает дополнительный «под водой» конструктор для Б.

Я чувствую, что это довольно странно: почему класс B не будет виден как a.k.o. поле в А? И: означает ли это, что класс B больше не является частным во время выполнения? И: почему поведение защищенного ключевого слова для класса B отличается?

public class A {
  public A() { b = new B(); }
  B b;
  protected class B { }
}

Ваш Ответ

4   ответа
-1

Вам нужно использовать

this.new B();
извините, но это. Новый B (); дает такое же предупреждение и поведение. Gerard
@ Крысы: это не будет иметь никакого значения для проблемы в руке. «Это» квалификация неявная.
25

Внутренние классы по сути являются хаком, введенным в Java 1.1. JVM на самом деле не имеет никакого представления о внутреннем классе, и поэтому компилятор должен его поддерживать. Компилятор генерирует класс B "outside" класса A, но в том же пакете, а затем добавляет синтетические средства доступа / конструкторы к нему, чтобы позволить A получить доступ к нему.

Когда вы предоставляете B защищенный конструктор, A может получить доступ к этому конструктору, поскольку он находится в том же пакете, без необходимости добавления синтетического конструктора.

ИМХО синтетические методы были ненужным дополнением к языку. Просто используя область действия пакета для & quot; приватной & quot; члены (что компилятор делает под капотом в любом случае) было удовлетворительным решением.
но участники все еще являются "частными" для других классов в пакете ...
Хорошо, я вижу это Для меня это означает, что я буду избегать использования внутренних классов, как в примере, это может привести только к путанице. Gerard
@CarlosHeuberger Я думаю, что это не «вся правда», см.answer Я только что опубликовал & # x2026;
Я бы не позволил этому беспокоить вас. Это конкретное предупреждение компилятора никому особо не нужно, синтетические методы все время используются с внутренними классами и не оказывают существенного влияния.
4

Я знаю, что этому вопросу уже почти три года, но я обнаружил, что на часть вопроса до сих пор нет ответа:

And: does it mean that class B is no longer private at run time?

Карлос Хойбергерс комментирует скаффмановский ответ, классB все ещеprivate для других классов в пакете.

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

Но поскольку JVM не имеет никакого понятия о внутреннем классе (как утверждает Скаффман), я спросил себя, как «доступ только для одного класса». видимость реализована на уровне байт-кода. Ответ: он вообще не реализован, для JVM внутренний класс выглядит как обычный закрытый класс пакета. Это если вы пишете байт-код для себя (или изменяете тот, что сгенерирован компилятором), вы можете получить доступ к классуB без проблем.

Вы также можете получить доступ ко всем синтетическим методам доступа из всех классов в одном пакете. Так что если вы присваиваете значение частному полю классаA в методе классаBв классе генерируется синтетический метод доступа с видимостью по умолчанию (то есть закрытым пакетом)A (назвал что-то вродеaccess$000), который устанавливает значение для вас. Этот метод должен вызываться только из классаB (и действительно, он может быть вызван только с использованием языка Java). Но с точки зрения JVM, это просто метод, как и любой другой, который может вызываться любым классом.

Итак, чтобы ответить на вопрос:

  • From the Java languages point of view, class B is and stays private.
  • From the JVMs point of view, class B (or better: class A$B) is not private.
правильно, но это не то, что я предложил. Я написал "members все еще приватны & quot; - Я имел в виду поля класса, а неclass сам как интерпретируемый вами! Также этот вопрос оjava и неbytecode (генерация, модификация,hacking ...).
@CarlosHeuberger, конечно, это не было обидно для вас! Конечно, члены класса B все еще являются частными, но класс B (как своего рода член класса A) - нет (с точки зрения JVM), и это был первоначальный вопрос Джерарда. И да, вопрос касается java, но, как указано в теге wiki: «Java - это язык программирования иruntime environment& Quot ;. А среда выполнения - это JVM, и JVM сама по себе не имеет ничего общего с языком программирования Java, а только интерпретирует байт-код.
2

Доступclass B и его конструктор не должен быть таким же. Вы можете иметь закрытый внутренний класс с конструктором области действия пакета, и это то, что я обычно делаю.

public class A {
  public A() { b = new B(); }
  B b;
  private class B {
    B() { }
  }
}
Но как вы можете иметь частный пакетный экземпляр правильно закрытого класса?

Похожие вопросы