一个类怎么能有自己类型的成员,这不是无限递归吗?

2022-08-31 15:02:30

假设我定义了一个类,该类的成员具有与自身相同类型的变量。

public class Abc {
    private Abc p;
}

这实际上有效,令我惊讶。

为什么我认为它不应该:创建一个实例,它包含一个类型的变量,其中包含一个类型的变量,其中包含一个类型的变量,它.....AbcAbcAbcAbc

显然我错了,有人可以启发我怎么做吗?


答案 1

您只是在声明变量,而不是创建它。尝试在声明或构造函数中创建它,并让我知道会发生什么:

public class Abc {
   private Abc p = new Abc(); // have fun!

   public static void main(String[] args) {
      new Abc();
   }
}

顺便说一句,如果您不在类中创建它,而是在 getter 方法或构造函数参数中接受对它的引用,则代码将正常工作。这就是一些链表的工作方式。


答案 2

区别在于编译时检查与运行时检查。

在第一种情况下(编译时),您声明在此实例中将具有对类型值的引用。编译器在检查正确的语义时会意识到这一点,并且由于它在编译时知道类型,因此它认为这没有问题。Abc

在第二种情况下(运行时),您实际上将为此引用创建一个值。这是你可能会给自己带来麻烦的地方。例如,如果您说了以下几句话:

public class Abc {
    private Abc p;

    public Abc() {
        p = new Abc();
    }
}

这可能会导致你陷入麻烦,原因正是你所引用的原因(不包含基本情况的递归,并且会不断分配内存,直到你运行 VM 的堆空间)。

但是,您仍然可以执行与此类似的操作,并避免无限递归。通过避免在构造期间创建值,可以将其推迟到调用方法之前。事实上,这是在 Java 中实现单例模式的常用方法之一。例如:

public class Abc {
    private Abc p;

    private Abc() {  // Private construction. Use singleton method
    }

    public static synchronized Abc getInstance() {
        if (p == null)
            p = new Abc();

        return p;
    }
}

这是完全有效的,因为您只创建该值的一个新实例,并且由于运行时已经加载了该类,因此它将知道实例变量的类型是有效的。