75 votes

Pourquoi cette instruction ne génère-t-elle pas une erreur StackOverflowError?

Je viens de voir cet étrange morceau de code dans une autre question. Je pensais que cela provoquerait un StackOverflowError , mais ça ne le fait pas ...

 public class Node {
    private Object one;
    private Object two;
    public static Node NIL = new Node(Node.NIL, Node.NIL);

    public Node(Object one, Object two) {
        this.one = one;
        this.two = two;
    }
}
 

Je pensais que ça allait exploser, à cause du Node.NIL référant à construire.

Je n'arrive pas à comprendre pourquoi.

101voto

Eran Points 35360

NIL est une variable statique. Il est initialisé une fois, quand la classe est initialisée. Lorsqu'il est initialisé, un seul Node instance est créée. La création de l' Node ne donne pas lieu à la création de tout autre Node des cas, donc, il n'est pas infinie de la chaîne d'appels. En passant Node.NIL de l'appel du constructeur a le même effet que la transmission d' null, depuis Node.NIL n'est pas encore initialisé lorsque le constructeur est appelé. Par conséquent, public static Node NIL = new Node(Node.NIL, Node.NIL); est le même que public static Node NIL = new Node(null, null);.

Si, d'autre part, NIL est une variable d'instance (et n'était pas passé comme argument à l' Node constructeur, car le compilateur aurait empêché de le transmettre au constructeur dans ce cas), il serait initialisé à chaque fois qu'une instance de Node a été créé, qui permettrait de créer un nouveau Node de l'instance, dont la création d'initialiser un autre NIL variable d'instance, conduisant à la chaîne infinie de constructeur appels qui permettrait de mettre fin, en StackOverflowError.

28voto

Peter Lawrey Points 229686

La variable NULLE est donné pour la première fois la valeur null puis initialisé une fois du haut vers le bas. Ce n'est pas une fonction et n'est pas définie de manière récursive. Tout champ statique que vous utilisez avant il est initialisé a la valeur par défaut et que votre code est le même que

public static Node {
    public static Node NIL;

    static {
        NIL = new Node(null /*Node.NIL*/, null /*Node.NIL*/);
    }

    public Node(Object one, Object two) {
        // Assign values to fields
    }
}

Ce n'est pas différent de l'écriture

NIL = null; // set implicitly
NIL = new Node(NIL, NIL);

Si vous avez défini une fonction ou méthode comme ceci, vous obtenez un StackoverflowException

Node NIL(Node a, Node b) {
    return NIL(NIL(a, b), NIL(a, b));
}

20voto

manouti Points 10398

La clé pour comprendre pourquoi il n'est pas une cause infinie inititialization est que lorsque la classe Node est en cours d'initialisation, la JVM en garde la trace et évite de ré-initialisation pendant un appel récursif référence à la classe dans son origine de l'initialisation. Ceci est détaillé dans cette section de la langue spec:

Parce que le langage de programmation Java est multithread, l'initialisation d'une classe ou d'une interface nécessite une synchronisation, depuis un autre thread peut être de l'initialisation de la même classe ou de l'interface en même temps. Il ya aussi la possibilité que l'initialisation d'une classe ou d'interface peut être demandée de manière récursive dans le cadre de l'initialisation de la classe ou de l'interface; par exemple, une variable d'initialiseur en classe pourrait appeler une méthode d'une autre classe B, qui à son tour pourrait appeler une méthode de la classe A. La mise en œuvre de la Machine Virtuelle Java est responsable de prendre soin de synchronisation et récursive d'initialisation à l'aide de la procédure suivante.

Ainsi, alors que l'initialiseur statique est la création de l'instance statique NIL, la référence à l' Node.NIL dans le cadre de l'appel du constructeur de ne pas re-exécuter l'initialiseur statique de nouveau. Au lieu de cela il a juste références quelle que soit la valeur de référence NIL a à cette époque, qu'est - null dans ce cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X