简体   繁体   English

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

[英]How JVM loads a class that has it's own reference

Consider the following code snippet: 考虑以下代码片段:

public class ListNode
{
    ListNode nextNode;

    //Constructors follow ...

   //Member methods follow ...
}

I don't know much about the internals of classloading, to me it looks like loading (Because class can never be created) will never complete because ListNode will keep trying to find the ListNode class, is it not? 我对类加载的内部知识不太了解,在我看来,加载(因为无法创建类)将永远不会完成,因为ListNode会继续尝试查找ListNode类,不是吗?

However this being one of the fundamentals of many data structures (LinkedList for example). 但是,这是许多数据结构(例如LinkedList)的基础之一。 It's obvious that it works. 显然,它可以工作。

So, how JVM interprets such a class definition and what is such references called in technical terms? 那么,JVM如何解释这样的类定义,以及这些引用在技术上又叫什么?

The class itself is only loaded once. 该类本身仅加载一次。 You're probably mistaking class for object. 您可能误以为是对象。 But even with objects, since the reference is empty (you're just declaring the variable, but not assigning anything), there is no problem. 但是即使有对象,由于引用为空(您只是声明变量,而不分配任何内容),所以没有问题。

It is possible to achieve what you suggest but it's not as easy as it sounds. 可以实现您的建议,但这并不像听起来那么容易。 A class can only be initialised in one thread and it can't accessed by another thread until this completes. 一个类只能在一个线程中初始化,并且在完成之前不能被另一个线程访问。

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");

    }
}

if you take a stack trace you see 如果您进行堆栈跟踪,您会看到

"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)

The main thread is waiting on the background thread to finish, however it can't get the value of NUM because the class hasn't finished initialising. 主线程正在等待后台线程完成操作,但是由于该类尚未完成初始化,因此无法获取NUM的值。

Points to remember 要记住的要点

1) The term itself wrong, you need to term it as class instantiation. 1)术语本身是错误的,您需要将其称为类实例化。

2) If you are thinking a class instantiation itself, the technical term is recursion and after sometime you run into stackoverlow error. 2)如果您自己在考虑类实例化,则技术术语为recursion并且在一段时间后遇到stackoverlow错误。

3)your code 3)您的代码

 public class ListNode
    {
        ListNode nextNode;

        //Constructors follow ...

       //Member methods follow ...
    }

is won't cause any stack overflow since you are not instantiating it, just declared it. 因为您没有实例化它,而只是声明了它,所以不会导致任何堆栈溢出。

4)The below code 4)下面的代码

 public class ListNode
    {
        ListNode nextNode = new ListNode();

        //Constructors follow ...

       //Member methods follow ...
    }

is stackoverflow since it instantiating itself . 自实例化以来是stackoverflow。

Your class definition simply contains a field declaration whose type is the class itself. 您的类定义仅包含一个字段声明,其类型为类本身。 It doesn't attempt to create an instance of the class. 它不会尝试创建该类的实例。 This poses no problem because the types of fields aren't even resolved when the class is being initialized. 这没有问题,因为在初始化类时甚至没有解析字段的类型。 For example, your field could even be of a type unknown to the runtime, but you wouldn't get a NoClassDefFoundError . 例如,您的字段甚至可能是运行时未知的类型,但不会得到NoClassDefFoundError By specification, you will get that error only when you actually refer to the type by trying to instantiate it, downcast into it, call a method with it in the signature, etc. 根据规范,只有当您通过尝试实例化,向下转换,在签名中调用带有该类型的方法等实际引用该类型时,才会出现该错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM