如何在 Java 中实例化内部 class 真的有效吗?

How instantiating an inner class in Java really works?

我正在从 innerclass 创建一个实例,但我不明白这个语法是什么意思。

OuterClass outerObject = new OuterClass();

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

我知道如果不从外部 OuterClass outerObject = new OuterClass(); 获取对象就无法从内部 class 获取对象,然后我们使用外部 class 的对象outerObject从内部classouterObject.new InnerClass();获取一个实例,那么OuterClass.InnerClass实际上意味着什么Java 文档中没有解释,因为它指出:

要实例化内部 class,您必须首先实例化外部 class。然后,使用以下语法在外部对象中创建内部对象 OuterClass.InnerClass innerObject = outerObject.new InnerClass();

如果我没记错的话,句法含义如下:

OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 
           InnerClass                                             The class InnerClass
          .                                                       which is an inner class of
OuterClass                                                        OuterClass
                      innerObject                                 has an instance named innerObject
                                  =                               which is assigned the value
                                                new InnerClass()  of a new InnerClass instance
                                               .                  such that when you use
                                                                  OuterClass.this from within
                                                                  InnerClass methods invoked on
                                                                  innerObject, it refers to
                                    outerObject                   outerObject.

这里的关键是内部classes是通过引用外部class创建的。如果你的 InnerClass 是静态的(一个 InnerClass 代表整个 OuterClass class),你会看到对外部 class 的引用是静态的:

static class InnerClass { ... }
...
//Initialization will become:
OuterClass.InnerClass innerObject = new OuterClass.InnerClass();
                                        ^ this part is a static OuterClass reference

另一方面,在您当前的情况下(InnerClass 不是静态的),内部 class 必须以对象的形式引用 OuterClass 创建 - outerObject。此外,您实际上可以通过引用 OuterClass.this:

从 InnerClass 访问 outerObject

OuterClass.java

public class OuterClass
{
  class InnerClass
  {
    public OuterClass getOuterClassReference()
    {
      return OuterClass.this;
    }
  }
}

Main.java

class Main
{
  public static void main(String[] args)
  {
    OuterClass outerObject = new OuterClass();
    OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 
    System.out.println(outerObject);
    System.out.println(innerObject.getOuterClassReference());
    System.out.println(outerObject == innerObject.getOuterClassReference());
  }
}

输出:

OuterClass@36baf30c
OuterClass@36baf30c
true

这里,输出中的36baf30c是任意内存地址。这两条输出线将始终相同。您可以清楚地看到,从 InnerClass 实例中引用 OuterClass.this 将 return 初始化时提供的 OuterClass 实例。这是您不能只调用 new InnerClass() 的部分原因 - 引用 OuterClass.this 在没有提供实例的情况下无法正确初始化。

这是 class 的名称,这样命名很可能是为了让编译器更容易找到定义。

如果您将变量声明为 InnerClass 类型,它将查找文件 InnerClass.java,但没有这样的文件。

圆点符号表示它实际上是 OuterClass 的成员,因此它将在文件 OuterClass.java.

中查找定义

这与使用图书馆中的 class 相同,

com.example.MyLibrary.ExternalClass myExternalObject;

JVM 对 OuterClassInnerClass 没有区别:类 都是 POJO 并且单独 类。但是 InnerClass 不是 static 因此它有内部 this 引用 OuterClass 的实例(因此它应该只用现有的 OuterClass 实例创建)

public class OuterClass {
    public class InnerClass {
        public OuterClass getOuterClassReference() {
            return OuterClass.this;
        }
    }
}

OuterClass outerObject = new OuterClass();
OuterClass.InnterClass innerObject = outerObject.new InnerClass(); // innerObject has this reference to outerObject

public class OuterClass {
    public static class InnerClass {}
}

OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = new OuterClass.InnerClass(); // innerObject does not have this reference to outerObject

换句话说,你可以像这样自己模拟InnterClass

public class OuterClass {   
}

public class InnerClass {
    private final OuterClass outer;

    public InnerClass(OuterClass outer) {
        this.outer = outer;
    }   
}

Outerclass.Innerclass只是内部类完整路径的一部分。
完整路径类似于 packagename.Outerclass.Innerclass.

因此, OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 真的和类似的东西没有什么不同:
java.util.ArrayList<T> varName = new java.util.ArrayList<T>();

您可以将内部 class 定义为 OuterClass

的静态成员
public class OuterClass {
    public static class StaticInnerClass {
        int i = 0;

        public String call() {
            i++;
            return this.getClass().getName() + " i=" + i;
        }
    }
}

所以定义静态内部class编译知道成员是一个class,内存区域在编译时实例化(它可以静态方式访问)并且你可以应用新的运算符和新运算符在另一个内存区域中实例化 class。

例如在主class

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

        /**
         * 
         *
         * @@@ New instance of Inner class
         */
        OuterClass.StaticInnerClass staticInnerClass = new OuterClass.StaticInnerClass();

        System.out.println(staticInnerClass.call());
        System.out.println(staticInnerClass.call());


        staticInnerClass = new OuterClass.StaticInnerClass();
        System.out.println("\n" + staticInnerClass.call());
        System.out.println(staticInnerClass.call());
    }
}

有输出

// new of inner class and i = 0
innerclass.OuterClass$StaticInnerClass i=1
innerclass.OuterClass$StaticInnerClass i=2

// new of inner class and i = 0 
innerclass.OuterClass$StaticInnerClass i=1
innerclass.OuterClass$StaticInnerClass i=2

参考文献:https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html.