JVM如何加载具有自己引用的类

时间:2015-08-21 12:12:56

标签: java classloader

请考虑以下代码段:

public class ListNode
{
    ListNode nextNode;

    //Constructors follow ...

   //Member methods follow ...
}

我对类加载的内部知识不太了解,对我而言看起来像加载(因为永远不能创建类)永远不会完成,因为ListNode将继续尝试查找ListNode类,不是吗?

然而,这是许多数据结构的基础之一(例如LinkedList)。很明显它有效。

那么,JVM如何解释这样的类定义以及技术术语中引用的引用是什么?

4 个答案:

答案 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。根据规范,只有当你通过尝试实例化它,向下转换它,在签名中用它调用方法等来实际引用类型时,你才会得到该错误。