假设我定义了一个类,该类具有与其自身相同类型的变量作为成员.
public class abc {
private abc p;
}
Run Code Online (Sandbox Code Playgroud)
这实际上是有效的,令我惊讶.
为什么我认为它不应该:创建一个实例abc,它包含一个类型的变量abc,其中包含一个类型的变量abc,其中包含一个类型的变量abc,其中.....
显然我错了,有人可以告诉我如何?
Hov*_*els 36
您只是声明变量而不是创建变量.尝试在声明或构造函数中创建它,让我知道会发生什么:
public class Abc {
private Abc p = new Abc(); // have fun!
public static void main(String[] args) {
new Abc();
}
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,如果您不在类中创建它,而是在getter方法或构造函数参数中接受对它的引用,那么您的代码将正常工作.这是一些链表的工作方式.
pse*_*ble 20
不同之处在于编译时与运行时检查.
在第一种情况(编译时)中,您声明abc在此实例中将引用type的值.编译器在检查正确的语义时会意识到这一点,并且因为它在编译时知道类型,所以它没有看到这个问题.
在第二种情况(运行时)中,您实际上将为此引用创建一个值以供参考.这是您可能遇到麻烦的地方.例如,如果您说以下内容:
public class abc {
private abc p;
public abc() {
p = new abc();
}
}
Run Code Online (Sandbox Code Playgroud)
这可能会因为您引用的确切原因而导致您遇到麻烦(递归不包含基本情况,并且会在您从堆空间中运行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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是完全有效的,因为您只创建了一个新的值实例,并且由于运行时已经加载了类,因此它将知道实例变量的类型是有效的.
rin*_*rer 10
当您想要为某些真实场景建模时,您可能必须使用此概念.例如,想一下Tree的分支.树的分支可能有n个分支.或者从计算机科学背景中,想一下链表的节点.节点将引用其旁边的节点.最后,next将包含一个null以指示列表的结尾.
所以,这只是一个引用,表明这种类型可能引用它自己的一种.而已.