Почему у нас не может быть статического метода в нестатическом внутреннем классе?
Если я сделаю внутренний класс статическим, он будет работать. Зачем?
java
class
static
inner-classes
Рахул Гарг
источник
источник
static
.»)Ответы:
Поскольку экземпляр внутреннего класса неявно связан с экземпляром его внешнего класса, он не может сам определять какие-либо статические методы. Поскольку статический вложенный класс не может напрямую ссылаться на переменные экземпляра или методы, определенные в его вмещающем классе, он может использовать их только через ссылку на объект, поэтому безопасно объявить статические методы в статическом вложенном классе.
источник
A.B.sync(X)
или даже (изнутри А)B.sync(x)
?Нет особого смысла разрешать статический метод в нестатическом внутреннем классе; как бы вы получили к нему доступ? Вы не можете получить доступ (по крайней мере на начальном этапе) к нестатическому экземпляру внутреннего класса, не пройдя через экземпляр внешнего класса. Не существует чисто статического способа создания нестатического внутреннего класса.
Для внешнего класса
Outer
вы можете получить доступ к статическому методуtest()
следующим образом:Для статического внутреннего класса
Inner
вы можете получить доступ к его статическому методуinnerTest()
следующим образом:Однако, если
Inner
он не является статическим, то теперь нет чисто статического способа ссылки на методinnertest
. Нестатические внутренние классы привязаны к конкретному экземпляру своего внешнего класса. Функция отличается от константы тем, что ссылка наOuter.Inner.CONSTANT
нее гарантированно будет однозначной, в отличие от вызова функцииOuter.Inner.staticFunction();
. Допустим, у вас естьInner.staticFunction()
те звонкиgetState()
, которые определены вOuter
. Если вы попытаетесь вызвать эту статическую функцию, теперь у вас будет неоднозначная ссылка на класс Inner. То есть, в каком экземпляре внутреннего класса вы вызываете статическую функцию? Это имеет значение. Видите, нет действительно статического способа ссылки на этот статический метод из-за неявной ссылки на внешний объект.Пол Беллора прав, что дизайнеры языка могли это допустить. Затем им пришлось бы тщательно запретить любой доступ к неявной ссылке на внешний класс в статических методах нестатического внутреннего класса. На этом этапе, каково значение этого внутреннего класса, если вы не можете ссылаться на внешний класс, кроме как статически? И если статический доступ в порядке, то почему бы не объявить весь внутренний класс статическим? Если вы просто сделаете внутренний класс статичным, то у вас не будет неявной ссылки на внешний класс, и у вас больше не будет этой неоднозначности.
Если вам действительно нужны статические методы для нестатического внутреннего класса, то вам, вероятно, нужно переосмыслить свой дизайн.
источник
Outer.Inner i = new Outer().new Inner();
Кроме того , внутренние классы будут разрешены , чтобы объявить статические константы в соответствии с JLS §15.28.Outer.Inner.staticMethod()
же, как вы можете получить доступOuter.Inner.CONSTANT
. «Вы не можете получить доступ к ... нестатическому экземпляру внутреннего класса, не пройдя экземпляр внешнего класса». Зачем вам нужен экземпляр? Вам не нужен экземплярOuter
для вызоваOuter.staticMethod()
. Я знаю, что это придирчиво, но я хочу сказать, что не имеет смысла формулировать ваш ответ таким образом. ИМХО, дизайнеры языка могли бы позволить это, если пожелают.Outer.Inner.CONSTANT
иOuter.Inner.staticMethod()
заключается в том, что ссылка на константу не имеет возможности неявно ссылаться на экземпляр,Outer
в которомInner
был создан экземпляр. Все ссылкиOuter.staticMethod()
имеют одинаковое точное состояние. Все ссылкиOuter.Inner.CONSTANT
имеют одинаковое точное состояние. Тем не менее, ссылки наOuter.Inner.staticMethod()
неоднозначны: «статическое» состояние не является действительно статическим из-за неявной ссылки на внешний класс в каждом экземпляреInner
. Нет по-настоящему однозначного, статичного способа получить к нему доступ.Outer.this
. Я согласен с разработчиками языка Java в том, что нет оснований разрешать статические методы или неконечные статические поля во внутренних классах, потому что все во внутреннем классе должно быть в контексте окружающего класса.У меня есть теория, которая может быть или не быть правильной.
Во-первых, вы должны знать кое-что о том, как внутренние классы реализованы в Java. Предположим, у вас есть этот класс:
Когда вы его компилируете, сгенерированный байт-код будет выглядеть так, как будто вы написали что-то вроде этого:
Теперь, если мы разрешили статические методы в нестатических внутренних классах, вы можете захотеть сделать что-то вроде этого.
... что выглядит довольно разумно, так как
Inner
класс, похоже, имеет одно воплощение наOuter
экземпляр. Но, как мы видели выше, нестатические внутренние классы на самом деле являются просто синтаксическим сахаром для статических «внутренних» классов, поэтому последний пример будет примерно эквивалентен:... который явно не будет работать, так
this$0
как не является статичным. Такого рода объясняется, почему статические методы не разрешены (хотя вы можете указать, что вы можете разрешить статические методы, если они не ссылаются на включающий объект), и почему у вас не может быть не финальных статических полей ( было бы нелогично, если бы экземпляры нестатических внутренних классов из разных объектов разделяли «статическое состояние»). Это также объясняет , почему конечные поля являются разрешено ( до тех пор , пока они не ссылаться на объекте ограждающего).источник
public static double sinDeg(double theta) { ... }
внутренний класс математических утилит?Единственная причина - «не обязательно», так зачем же его поддерживать?
Синтаксически, нет причин запрещать внутреннему классу иметь статические члены. Несмотря на то, что экземпляр
Inner
связан с экземпляромOuter
, его все равно можно использоватьOuter.Inner.myStatic
для ссылки на статический член,Inner
если java решит это сделать.Если вам нужно поделиться чем-то среди всех экземпляров
Inner
, вы можете просто поместить их вOuter
качестве статических членов. Это не хуже, чем вы используете статические члены вInner
, гдеOuter
все равно может получить доступ к любому частному членуInner
(не улучшает инкапсуляцию).Если вам нужно разделить что-то между всеми экземплярами,
Inner
созданными однимouter
объектом, имеет смысл поместить их вOuter
класс как обычные члены.Я не согласен с мнением о том, что «статический вложенный класс - это просто класс высшего уровня». Я думаю, что лучше рассматривать статический вложенный класс / внутренний класс как часть внешнего класса, потому что они могут получить доступ к закрытым членам внешнего класса. И члены внешнего класса также являются «членами внутреннего класса». Поэтому нет необходимости поддерживать статический член во внутреннем классе. Обычного / статического члена во внешнем классе будет достаточно.
источник
От: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Объяснение Оракула поверхностное и сложное. Поскольку нет технической или синтаксической причины для вытеснения статических членов внутри внутреннего класса (это допускается в других языках, таких как C #), мотивация разработчиков Java была, скорее всего, концептуальным вкусом и / или вопросом технического удобства.
Вот мое предположение:
В отличие от классов верхнего уровня, внутренние классы зависят от экземпляра: экземпляр внутреннего класса связан с экземпляром каждого из его внешних классов и имеет прямой доступ к их членам. Это главная мотивация их наличия на Java. Выражается иначе: внутренний класс предназначен для создания экземпляров в контексте экземпляра внешнего класса. Без экземпляра внешнего класса внутренний класс не должен быть более пригодным для использования, чем другие члены экземпляра внешнего класса. Давайте назовем это как зависящий от экземпляра дух внутренних классов.
Сама природа статических членов (которые НЕ являются объектно-ориентированными) вступает в противоречие с зависимым от экземпляра духом внутренних классов (которые являются объектно-ориентированными), потому что вы можете ссылаться на статический член внутреннего класса без вызова экземпляра внешнего класса и вызывать его. используя полное имя внутреннего класса.
В частности, статические переменные могут нарушать еще один способ: два экземпляра внутреннего класса, которые связаны с разными экземплярами внешнего класса, будут совместно использовать статические переменные. Поскольку переменные являются компонентом состояния, два экземпляра внутреннего класса, по сути, будут совместно использовать состояние независимо от экземпляров внешнего класса, с которыми они связаны. Это не значит, что недопустимо, чтобы статические переменные работали таким образом (мы принимаем их в Java как разумный компромисс с чистотой ООП), но, возможно, есть более глубокое нарушение, если допустить их во внутренних классах, экземпляры которых уже связаны с экземплярами внешнего класса по дизайну. Запрещение статических членов внутри внутренних классов в пользу духа, зависящего от экземпляра, приносит дополнительный бонус в виде предотвращения этого более глубокого нарушения ООП.
С другой стороны, никакие такие правонарушения не связаны со статическими константами, которые по сути не составляют состояние и поэтому допустимы. Почему бы не запретить статические константы для максимального соответствия духу, зависящему от экземпляра ? Возможно, потому что константы не должны занимать больше памяти, чем необходимо (если они вынуждены быть нестатичными, они копируются в каждый экземпляр внутреннего класса, который потенциально расточителен). В противном случае я не могу представить причину исключения.
Возможно, это не слишком убедительная аргументация, но, по мнению IMO, она наиболее понятна из беглого замечания Oracle по этому вопросу.
источник
Короткий ответ: ментальная модель, которую имеет большинство программистов о том, как работает область, не является моделью, используемой javac. Соответствие более интуитивной модели потребовало бы больших изменений в том, как работает javac.
Основная причина того, что статические члены во внутренних классах желательны, заключается в чистоте кода - статический член, используемый только внутренним классом, должен жить внутри него, а не помещаться во внешний класс. Рассматривать:
Рассмотрим, что происходит в getID (), когда я использую неквалифицированный идентификатор «outID». Область, в которой появляется этот идентификатор, выглядит примерно так:
Здесь, опять же, поскольку именно так работает javac, уровень Outer области включает в себя как статические, так и элементы экземпляра Outer. Это сбивает с толку, потому что нам обычно говорят о статической части класса как о другом уровне области видимости:
В этом смысле, конечно, staticMethod () может видеть только статические члены Outer. Но если бы именно так работал javac, то ссылка на переменную экземпляра в статическом методе привела бы к ошибке «имя не может быть разрешено». На самом деле происходит то, что имя находится в области видимости, но затем включается дополнительный уровень проверки и выясняется, что имя было объявлено в контексте экземпляра и на него ссылаются из статического контекста.
Хорошо, как это относится к внутренним классам? Наивно, мы думаем, что нет причин, по которым у внутренних классов не может быть статической области видимости, потому что мы изображаем область видимости, работая так:
Другими словами, статические объявления во внутреннем классе и объявления экземпляров во внешнем классе находятся в области видимости в контексте экземпляра внутреннего класса, но ни одно из них на самом деле не вложено в другой; оба вместо этого вложены в статическую область Outer.
Это просто не то, как работает javac - существует один уровень области видимости как для статических элементов, так и для элементов экземпляра, и область действия всегда строго вложена. Даже наследование реализуется путем копирования объявлений в подкласс, а не ветвления и поиска в области суперкласса.
Для поддержки статических членов внутренних классов javac должен был бы либо разделить статические области и области экземпляров и поддерживать ветвящиеся и воссоединяющиеся иерархии областей действия, либо он должен был бы расширить свою простую логическую идею «статического контекста», чтобы изменить ее, чтобы отслеживать тип контекста на всех уровнях. вложенного класса в текущей области.
источник
Примечание. Нестатический вложенный класс называется внутренним классом, поэтому его у вас нет
non-static inner class
.Экземпляр внутреннего класса не существует без соответствующего экземпляра внешнего класса. Внутренний класс не может объявлять статические члены, кроме констант времени компиляции. Если бы это было разрешено, то была бы неясность в отношении значения
static
. В этом случае были бы определенные заблуждения:Именно поэтому дизайнеры, вероятно, приняли решение вообще не заниматься этим вопросом.
Опять же, вы не можете сделать внутренний класс статическим, вы можете объявить статический класс как вложенный. В этом случае этот вложенный класс фактически является частью внешнего класса и может иметь статические члены без каких-либо проблем.
источник
Эта тема привлекла внимание многих, но я постараюсь объяснить в самых простых терминах.
Во-первых, со ссылкой на http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 класс или интерфейс инициализируются непосредственно перед первым вхождением / вызовом любого члена, которому предшествует ключевое слово static.
Итак, если мы будем мириться со статическим членом внутри внутреннего класса, это приведет к инициализации внутреннего класса, а не обязательно внешнего / включающего класса. Таким образом, мы затрудняем последовательность инициализации класса.
Также учтите тот факт, что нестатический внутренний класс связан с экземпляром внешнего / внешнего класса. Таким образом, связь с экземпляром будет означать, что внутренний класс будет существовать внутри экземпляра внешнего класса и будет отличаться среди экземпляров.
Упрощение точки: для доступа к статическому члену нам нужен экземпляр класса Outer, из которого нам снова нужно будет создать экземпляр нестатического внутреннего класса. Статические члены не должны быть привязаны к экземплярам, и поэтому вы получаете ошибку компиляции.
источник
Внутренний класс - это нечто совершенно отличное от статического вложенного класса, хотя оба синтаксиса похожи. Статические вложенные классы являются лишь средством группировки, тогда как внутренние классы имеют сильную ассоциацию и доступ ко всем значениям своего внешнего класса. Вы должны быть уверены, почему вы хотите использовать внутренний класс, и тогда он должен быть вполне естественным, какой вы должны использовать. Если вам нужно объявить статический метод, это, вероятно, статический вложенный класс, который вам нужен.
источник
Предположим, что есть два экземпляра внешнего класса, и у них обоих есть экземпляр внутреннего класса. Теперь, если у внутреннего класса есть один статический член, он будет хранить только одну копию этого члена в области кучи. В этом случае оба объекта внешнего класса будут ссылаться на это. единственная копия, и они могут изменить ее вместе. Это может привести к ситуации «Грязного чтения», следовательно, для предотвращения этого ограничения Java применил это ограничение. Еще один сильный аргумент в поддержку этого аргумента состоит в том, что java разрешает использовать конечные статические члены, те, чьи значения не могут быть изменено с любого из объекта внешнего класса. Пожалуйста, дайте мне, если я ошибаюсь.
источник
Прежде всего, почему кто-то хочет определить статический член в нестатическом внутреннем классе? Ответ таков: внешний член класса может использовать эти статические члены только с внутренним именем класса, верно?
Но для этого случая мы можем напрямую определить член во внешнем классе. который будет связан со всем объектом внутреннего класса, внутри экземпляра внешнего класса.
как ниже код,
можно написать так
Так что, по моему мнению, не усложнять код Java-дизайнер не позволяет эту функциональность, или мы можем увидеть эту функциональность в будущих выпусках с некоторыми дополнительными функциями.
источник
Попробуйте относиться к классу как к нормальному полю, тогда вы поймете.
источник
Бесполезно иметь внутренние классы как статические, потому что вы не сможете получить к ним доступ с самого начала.
Подумайте об этом, чтобы получить доступ к статическому члену, вы используете className.memberName ,, в нашем случае это должно быть что-то вроде externalclassName.innerclassName.memberName ,,, теперь вы понимаете, почему innerclass должен быть статическим ....
источник
Вам разрешены статические методы для статических вложенных классов. Например
источник