Почему у нас не может быть статического метода в нестатическом внутреннем классе?
Если я сделаю внутренний класс статическим, он будет работать. Зачем?
static
.»)
Почему у нас не может быть статического метода в нестатическом внутреннем классе?
Если я сделаю внутренний класс статическим, он будет работать. Зачем?
static
.»)
Ответы:
Поскольку экземпляр внутреннего класса неявно связан с экземпляром его внешнего класса, он не может сам определять какие-либо статические методы. Поскольку статический вложенный класс не может напрямую ссылаться на переменные экземпляра или методы, определенные в его вмещающем классе, он может использовать их только через ссылку на объект, поэтому безопасно объявить статические методы в статическом вложенном классе.
A.B.sync(X)
или даже (изнутри А) B.sync(x)
?
Нет особого смысла разрешать статический метод в нестатическом внутреннем классе; как бы вы получили к нему доступ? Вы не можете получить доступ (по крайней мере на начальном этапе) к нестатическому экземпляру внутреннего класса, не пройдя через экземпляр внешнего класса. Не существует чисто статического способа создания нестатического внутреннего класса.
Для внешнего класса Outer
вы можете получить доступ к статическому методу test()
следующим образом:
Outer.test();
Для статического внутреннего класса Inner
вы можете получить доступ к его статическому методу innerTest()
следующим образом:
Outer.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. Предположим, у вас есть этот класс:
class Outer {
private int foo = 0;
class Inner implements Runnable {
public void run(){ foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(); }
}
Когда вы его компилируете, сгенерированный байт-код будет выглядеть так, как будто вы написали что-то вроде этого:
class Outer {
private int foo = 0;
static class Inner implements Runnable {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public void run(){ this$0.foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(this); }
}
Теперь, если мы разрешили статические методы в нестатических внутренних классах, вы можете захотеть сделать что-то вроде этого.
class Outer {
private int foo = 0;
class Inner {
public static void incrFoo(){ foo++; }
}
}
... что выглядит довольно разумно, так как Inner
класс, похоже, имеет одно воплощение на Outer
экземпляр. Но, как мы видели выше, нестатические внутренние классы на самом деле являются просто синтаксическим сахаром для статических «внутренних» классов, поэтому последний пример будет примерно эквивалентен:
class Outer {
private int foo = 0;
static class Inner {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public static void incrFoo(){ this$0.foo++; }
}
}
... который явно не будет работать, так 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.
Основная причина того, что статические члены во внутренних классах желательны, заключается в чистоте кода - статический член, используемый только внутренним классом, должен жить внутри него, а не помещаться во внешний класс. Рассматривать:
class Outer {
int outID;
class Inner {
static int nextID;
int id = nextID++;
String getID() {
return outID + ":" + id;
}
}
}
Рассмотрим, что происходит в getID (), когда я использую неквалифицированный идентификатор «outID». Область, в которой появляется этот идентификатор, выглядит примерно так:
Outer -> Inner -> getID()
Здесь, опять же, поскольку именно так работает javac, уровень Outer области включает в себя как статические, так и элементы экземпляра Outer. Это сбивает с толку, потому что нам обычно говорят о статической части класса как о другом уровне области видимости:
Outer static -> Outer instance -> instanceMethod()
\----> staticMethod()
В этом смысле, конечно, staticMethod () может видеть только статические члены Outer. Но если бы именно так работал javac, то ссылка на переменную экземпляра в статическом методе привела бы к ошибке «имя не может быть разрешено». На самом деле происходит то, что имя находится в области видимости, но затем включается дополнительный уровень проверки и выясняется, что имя было объявлено в контексте экземпляра и на него ссылаются из статического контекста.
Хорошо, как это относится к внутренним классам? Наивно, мы думаем, что нет причин, по которым у внутренних классов не может быть статической области видимости, потому что мы изображаем область видимости, работая так:
Outer static -> Outer instance -> Inner instance -> getID()
\------ Inner static ------^
Другими словами, статические объявления во внутреннем классе и объявления экземпляров во внешнем классе находятся в области видимости в контексте экземпляра внутреннего класса, но ни одно из них на самом деле не вложено в другой; оба вместо этого вложены в статическую область 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 разрешает использовать конечные статические члены, те, чьи значения не могут быть изменено с любого из объекта внешнего класса. Пожалуйста, дайте мне, если я ошибаюсь.
Прежде всего, почему кто-то хочет определить статический член в нестатическом внутреннем классе? Ответ таков: внешний член класса может использовать эти статические члены только с внутренним именем класса, верно?
Но для этого случая мы можем напрямую определить член во внешнем классе. который будет связан со всем объектом внутреннего класса, внутри экземпляра внешнего класса.
как ниже код,
public class Outer {
class Inner {
public static void method() {
}
}
}
можно написать так
public class Outer {
void method() {
}
class Inner {
}
}
Так что, по моему мнению, не усложнять код Java-дизайнер не позволяет эту функциональность, или мы можем увидеть эту функциональность в будущих выпусках с некоторыми дополнительными функциями.
Попробуйте относиться к классу как к нормальному полю, тогда вы поймете.
//something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class
Outer.something
Бесполезно иметь внутренние классы как статические, потому что вы не сможете получить к ним доступ с самого начала.
Подумайте об этом, чтобы получить доступ к статическому члену, вы используете className.memberName ,, в нашем случае это должно быть что-то вроде externalclassName.innerclassName.memberName ,,, теперь вы понимаете, почему innerclass должен быть статическим ....