请考虑以下代码段:
public class ListNode
{
ListNode nextNode;
//Constructors follow ...
//Member methods follow ...
}
我对类加载的内部知识不太了解,对我而言看起来像加载(因为永远不能创建类)永远不会完成,因为ListNode将继续尝试查找ListNode类,不是吗?
然而,这是许多数据结构的基础之一(例如LinkedList)。很明显它有效。
那么,JVM如何解释这样的类定义以及技术术语中引用的引用是什么?
答案 0 :(得分:2)
类本身只加载一次。你可能把对象误认为是对象。但即使是对象,由于引用是空的(你只是声明变量,但没有分配任何东西),所以没有问题。
答案 1 :(得分:2)
可以达到你的建议,但它并不像听起来那么容易。一个类只能在一个线程中初始化,并且在完成之前它不能被另一个线程访问。
public class Main {
static class Deadlock {
static int NUM = 1;
static {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// tries to use NUM in a new thread
System.out.println(NUM);
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
}
public static void main(String[] args) {
System.out.println("About to dead lock");
new Deadlock();
System.out.println(".. never gets here");
}
}
如果你采用堆栈跟踪,你会看到
"Thread-0" #11 prio=5 os_prio=0 tid=0x00007f9c2414a800 nid=0x2188 in Object.wait() [0x00007f9be983b000]
java.lang.Thread.State: RUNNABLE
at Main$Deadlock$1.run(Main.java:14)
at java.lang.Thread.run(Thread.java:745)
"main" #1 prio=5 os_prio=0 tid=0x00007f9c2400a000 nid=0x2163 in Object.wait() [0x00007f9c2caf0000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000fec64ec0> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1245)
- locked <0x00000000fec64ec0> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1319)
at Main$Deadlock.<clinit>(Main.java:19)
at Main.main(Main.java:28)
主线程正在等待后台线程完成,但由于该类尚未完成初始化,因此无法获取NUM的值。
答案 2 :(得分:1)
要记住的要点
1)这个词本身就错了,你需要把它称为类实例化。
2)如果你正在考虑一个类实例化,那么技术术语是recursion
,并且在某个时候你遇到stackoverlow
错误。
3)你的代码
public class ListNode
{
ListNode nextNode;
//Constructors follow ...
//Member methods follow ...
}
不会导致任何堆栈溢出,因为你没有实例化它,只是声明它。
4)以下代码
public class ListNode
{
ListNode nextNode = new ListNode();
//Constructors follow ...
//Member methods follow ...
}
是stackoverflow,因为它实例化了自己。
答案 3 :(得分:1)
您的类定义只包含一个字段声明,其类型是类本身。它不会尝试创建类的实例。这没有问题,因为在初始化类时甚至没有解析字段类型。例如,您的字段甚至可能是运行时未知的类型,但您不会得到NoClassDefFoundError
。根据规范,只有当你通过尝试实例化它,向下转换它,在签名中用它调用方法等来实际引用类型时,你才会得到该错误。