more fun with class initializers

Date view Thread view Subject view Author view

From: Godmar Back (gback@marker.cs.utah.edu)
Date: Wed Nov 18 1998 - 01:35:57 EST


The fact that you on one hand are able to construct an object of a given
class before the static initializer has finished, but on the other
hand have to wait until it finishes before it's clear whether a class
is "usable" leads to funny phenomena. See the test.

What that means is that there's another state in which a class can
be in: One in which it's okay to create instances via newInstance(),
but it's not okay to access it in Java code nor is it btw okay to use
reflection such as getField on it.

A class is put in that new state before we call the static initializer.
Now we must distinguish between operations that require the class
completely and successfully initialized (that is, with no
ExceptionInInitializerError), and those for which it is sufficient
that the linking has proceeded to the state right before calling out
to the static initializers.

This seems damn confusing.

        - Godmar

/**
 * ???
 *
 * @author Godmar Back <gback@cs.utah.edu>
 */
import java.util.Vector;
import java.lang.reflect.*;

class Base {
    static boolean useme;

    static {
        Base b = new Base();
        ProcessClassInst.v.addElement(b);
        useme = true;

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) { }
        ((Object)null).toString();
    }
    public String toString() { return "a base"; }
}

public class ProcessClassInst
{
    static Vector v = new Vector();

    public static void main(String av[]) throws Exception {
        // a watchdog thread that kills us off after 3 sec
        new Thread() {
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println("sorry, you timed out");
                    System.exit(-1);
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }.start();

        // a thread that will load Sub and Base
        Thread t = new Thread() {
            public void run() {
                try {
                    Class.forName("Base");
                } catch (Throwable t) {
                    // System.out.println(t);
                }
            }
        };
        t.start();
        Thread.sleep(1000);

        // nobody knows yet whether that should succeed...
        new Thread() {
            public void run() {
                try {
                    System.out.println(new Base());
                } catch (Throwable tt) {
                    System.out.println(tt);
                }
            }
        }.start();

        System.out.println(v.elementAt(0).getClass().newInstance());
        Thread t2 = new Thread() {
            public void run() {
                try {
                    System.out.println(v.elementAt(0).getClass().newInstance());
                } catch (Throwable t) {
                    System.out.println(t);
                }
            }
        };
        t2.start();
        t2.join();
        System.exit(0);
    }
}


Date view Thread view Subject view Author view

This archive was generated by hypermail 2b29 : Sat Sep 23 2000 - 19:57:03 EDT