如何在Java中实例化内部类真正起作用?

 2021-02-24 

How instantiating an inner class in Java really works?

我正在从内部类中创建一个实例,但我不明白此语法的含义。

1
2
3
OuterClass outerObject = new OuterClass();

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

我知道如果不从外部类OuterClass outerObject = new OuterClass();中获取对象,就无法从内部类中获取对象,然后我们使用外部类externalObject的对象从内部类outerObject.new InnerClass();中获取实例。 ,因此OuterClass.InnerClass的实际含义是,因为Java文档中没有说明它,因为它指出:

要实例化内部类,必须首先实例化外部类。然后,使用此语法OuterClass.InnerClass innerObject = outerObject.new InnerClass();

在外部对象内创建内部对象


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

1
2
3
4
5
6
7
8
9
10
11
12
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.

关键是内部类是通过引用外部类来创建的。如果您的InnerClass是静态的(整个OuterClass类一个InnerClass),您将看到对外部类的引用是静态的:

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

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

从InnerClass中访问outerObject

OuterClass.java

1
2
3
4
5
6
7
8
9
10
public class OuterClass
{
  class InnerClass
  {
    public OuterClass getOuterClassReference()
    {
      return OuterClass.this;
    }
  }
}

Main.java

1
2
3
4
5
6
7
8
9
10
11
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将返回初始化时提供的OuterClass实例。这是不能只调用new InnerClass()的原因的一部分-无法在没有实例的情况下正确初始化引用OuterClass.this


JVM在OuterClassInnerClass之间没有区别:这两个类都是POJO和单独的类。但是InnerClass不是static,因此它具有内部this引用OuterClass的实例(因此,应仅使用存在的OuterClass实例创建它)

1
2
3
4
5
6
7
8
9
10
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
1
2
3
4
5
6
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

1
2
3
4
5
6
7
8
9
10
public class OuterClass {  
}

public class InnerClass {
    private final OuterClass outer;

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

这是类的名称,很可能以此方式命名,以使编译器更容易找到定义。

如果将变量声明为只是InnerClass类型,它将查找文件InnerClass.java,但没有此类文件。

点符号表示它实际上是OuterClass的成员,因此它将在文件OuterClass.java中查找定义。

这与使用库中的类相同,

1
com.example.MyLibrary.ExternalClass myExternalObject;

您可以将内部类定义为OuterClass的静态成员

1
2
3
4
5
6
7
8
9
10
public class OuterClass {
    public static class StaticInnerClass {
        int i = 0;

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

因此,在定义静态内部类时,编译器知道成员是一个类,存储区在编译时被实例化(可以以静态方式访问),并且您可以将new运算符和new运算符实例应用于另一个类中内存区域。

例如在主类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Main {
    public static void main(String[] args) {

        /**
         * https://stackoverflow.com/questions/57581397/how-instantiating-an-inner-class-in-java-really-works
         *
         * @@@ 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("\
"
+ staticInnerClass.call());
        System.out.println(staticInnerClass.call());
    }
}

带输出

1
2
3
4
5
6
7
// 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。


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

因此,
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
确实与以下内容没有什么不同:
java.util.ArrayList<T> varName = new java.util.ArrayList<T>();