Почему `Outer.Inner inner = o.new Inner ();` не `Outer.Inner inner = o.new Outer.Inner ();`? - PullRequest
3 голосов
/ 22 мая 2019
class Outer {    
    class Inner {       

    }    
}

public class Demo {
    public static void main(String args[]) {

        Outer o = new Outer();
        Outer.Inner inner = o.new Inner();    

    }    
}

Почему

Outer.Inner inner = o.new Inner();

не

Outer.Inner inner = o.new Outer.Inner();

то есть, почему квалифицируется объявление типа inner с именем внешнего класса, но не квалифицируется конструктор внутреннего класса симя внешнего класса?

Спасибо.

Ответы [ 3 ]

5 голосов
/ 22 мая 2019

Поскольку o уже является экземпляром типа Outer, вам не нужно создавать другой экземпляр Outer для создания экземпляра Inner.Вторая опция, которую вы перечисляете, подразумевает, что вы создаете экземпляр другого внутреннего класса с именем Outer внутри верхнего уровня Outer, которого нет, и он выдаст ошибку.(Правка: только что заметил, что после o.new Outer нет скобок, что заставляет меня думать, что вы, вероятно, рассуждали о моем втором абзаце).

Если вы имеете в виду, что Outer.Inner() должен быть конструкторома не просто Inner(), это потому, что Outer.Inner() подразумевает Inner статический внутренний класс.static никогда не указывалось, поэтому вам необходим экземпляр Outer.

3 голосов
/ 22 мая 2019

Из JLS 15.9 вы говорите о выражении создания экземпляра квалифицированного класса :

выражениях создания экземпляра квалифицированного класса начинаются с Primary выражения или ExpressionName

(Ваш начинается с основного выражения)

Синтаксис задается как:

ClassInstanceCreationExpression:
  UnqualifiedClassInstanceCreationExpression
  ExpressionName . UnqualifiedClassInstanceCreationExpression
  Primary . UnqualifiedClassInstanceCreationExpression

UnqualifiedClassInstanceCreationExpression:
  new [TypeArguments] ClassOrInterfaceTypeToInstantiate ( [ArgumentList] ) [ClassBody]

ClassOrInterfaceTypeToInstantiate:
  {Annotation} Identifier {. {Annotation} Identifier} [TypeArgumentsOrDiamond]

TypeArgumentsOrDiamond:
  TypeArguments 
  <>

Чуть ниже в 15.9.1 написано:

* Identifier в ClassOrInterfaceTypeToInstantiate должно однозначно обозначать внутренний класс, который доступен, не является окончательным, не тип enum, а член типа времени компиляции выражения Primary или ExpressionName.В противном случае возникает ошибка времени компиляции.

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

Было бы просто излишним указывать Outer..

0 голосов
/ 22 мая 2019

Для сравнения:

public class Demo {
    public static void foo(){
       System.out.println("Hello world!");
    }
}

Мы можем foo двумя способами:

1)

Demo.foo();  // with Demo qualifier

2)

Demo d = new Demo();
d.foo();  // without Demo qualifier!
...