Статьи

Что является частным в Java 9?

Во время интервью я чувствую, что большинство кандидатов не знают, что на самом деле означает частный модификатор в Java. Они знают что-то об этом, что достаточно для повседневного кодирования, но далеко не завершено. Это не проблема. Знание достаточно, ну … достаточно. Но все же интересно знать некоторые внутренние принципы работы Java. В некоторых редких случаях это может пролить свет на некоторые детали. Если ничего другого, то это развлекает .orElse(whyDoYouReadIt) ?

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

Эта статья должна описать некоторые факты Java, надеюсь, немного более читабельно, чем чтение языкового стандарта.

Так что же такое личное?

private — это модификатор доступа в Java. Если у вас есть private член (метод, поле, внутренний или вложенный класс или вложенный интерфейс) класса, он может использоваться только кодом, который находится в том же классе. Интересный вопрос: что происходит, когда существует более одного класса, в котором находится private метод? Как это может быть в более чем одном классе? Если есть класс, который содержит другой класс, и есть внутренний метод внутри внутреннего / вложенного класса, то он находится внутри внутреннего / вложенного класса, а также в классе верхнего уровня.

Может ли закрытый метод внутри закрытого класса вызываться из внешнего класса? Может ли код внутри закрытого класса вызвать закрытый метод во внешнем классе? Ответ да в обоих случаях. Пример кода

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package javax0.package1;
 
class TopLevelClass {
 
  void topMethod(){
    NestedClass nc = new NestedClass();
    nc.method();
  }
   
  private int z;
 
  interface NestedInterface {
    default void method(){
      TopLevelClass tlc = new TopLevelClass();
      tlc.z++;
    }
  }
 
  static class NestedClass {
    private int k;
 
    private void method() {
      TopLevelClass tlc = new TopLevelClass();
      k = tlc.z;
    }
  }
}

ясно показывает эту ситуацию: вложенный класс NestedClass и вложенный интерфейс NestedInterface содержат код, который может обращаться к внешнему классу, содержащему private поле z . Аналогичным образом код класса верхнего уровня может вызывать закрытый метод внутри вложенного класса. Тот факт, что этот пример кода на самом деле не выполняет ничего разумного, в этом случае не важен.

Если мы скомпилируем этот единственный исходный файл, мы получим три файла классов:

  1. TopLevelClass$NestedClass.class
  2. TopLevelClass$NestedInterface.class
  3. TopLevelClass.class

Это потому, что JVM не знает, что является верхним уровнем и что является вложенным. JVM ничего не знает о вложенных классах и классах верхнего уровня. Для JVM класс — это просто класс. Класс высшего уровня, если вы настаиваете. Это происходит главным образом потому, что язык Java 1.0 не имел вложенных и внутренних классов, а JVM была разработана в соответствии с этим. Когда в Java 1.1 были представлены внутренние и вложенные классы, компиляция была изменена только вместо JVM, так что внутренние и вложенные классы оставались языковой функцией, но не обрабатывались JVM напрямую.

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

Что действительно происходит, так это то, что компилятор генерирует специальные методы получения и установки для получения доступа к полю z .

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

Это также интересная ошибка, так как считается, что приватное поле (или что-то еще) доступно только из одного и того же объекта. Это обычный способ, которым мы используем эти члены при программировании, но если код имеет ссылку на другой экземпляр того же типа, то через эту ссылку мы можем получить доступ к закрытым полям другого объекта так же хорошо, как мы можем получить доступ к «нашему собственные »поля. Это редкий случай? Вы можете думать, потому что вы редко программируете это. Но в действительности это происходит очень часто: IDE обычно генерирует код для нас, и поэтому некоторые разработчики не думают об этом. Без этого вряд ли можно было бы закодировать метод классов equals(Object other) .

А как насчет Java 9?

Пока в этой статье нет ничего конкретного о Java 9, и в наши дни каждая статья о Java должна быть о Java 9 (или уже 10?).

Если мы посмотрим на контроль доступа в целом, то мы должны поговорить о JPMS, и есть много хороших статей об этом. У codeFx есть хороший список статей об этом. У Стивена Колебурна есть хорошие статьи.

Вскоре вы сможете даже купить книги о модульных системах Java у разных издателей. Мне повезло, что я уже могу прочитать один черновик от Пакта как рецензент, и мне это нравится. Но JPMS не меняет «частный» на этом уровне. Тем не менее, вложенные классы, внутренние классы и методы-мосты будут точно такими же, как и раньше.

Небольшая разница в том, что Java 9 теперь имеет закрытые методы внутри интерфейсов. Это означает, что теперь мы должны быть готовы иметь методы синтаксического моста не только во внутренних и вложенных классах, но и в интерфейсах.

Takeway …

Иногда самые простые вещи не так просты, как кажутся. В конце концов, все ИТ-технологии, наука, инженерия — это не что иное, как куча нулей и единиц. Просто у нас их много. Действительно много. Если в этой статье было что-то новое для вас, то вам следует сказать, что в языке Java и в JVM есть области, которые вам, возможно, будет интересно изучить немного подробнее. Например:

  • В чем разница между вложенным и внутренним классом?
  • Можете ли вы иметь вложенный интерфейс внутри класса и аналогичным образом вы можете иметь внутренний интерфейс внутри класса?
  • Как насчет классов или интерфейсов внутри интерфейса? Можете ли вы иметь внутренний класс в интерфейсе? Как насчет вложенного класса?
  • Можете ли вы написать код, используя отражение, в котором перечислены все методы, которые есть у класса? Это перечислит синтетические методы? Какие модификаторы у него будут?
  • Когда вы компилируете внутренний класс, он будет иметь скомпилированное имя Outer$Inner.class , которое является допустимым именем. Но что произойдет, если существует исходный файл Outer$Inner.java ? Разберись!
  • Сгенерированные синтетические методы также имеют легитимные имена. Что произойдет, если вы определите метод с этим именем? Это спецификация Java или конкретная реализация, что вы видите?
  • Насколько глубоко вы можете вкладывать внутренние и вложенные классы и / или интерфейсы? Может ли вложенный класс содержать внутренний класс? Может ли внутренний класс содержать вложенный класс?
  • Как вы думаете, почему в JDK нет символического имени для синтетического модификатора? Почему фактическое значение модификатора может совпадать со значением для volatile полей?
  • Можете ли вы иметь статическое поле, класс или метод внутри вложенного класса?

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

Последний вопрос с подвохом, даже менее практичный, чем приведенный выше, только для развлечения, если хотите:

Головоломка

Мы знаем, что невозможно иметь статическое поле внутри внутреннего (не вложенного) класса. Возможно ли по-прежнему иметь скомпилированный файл класса, сгенерированный компилятором Java из внутреннего класса, который имеет статический метод?

Ссылка: Что является частным в Java 9? от нашего партнера JCG Питера Верхаса из блога Java Deep .