Search code examples
javaeclipsedebuggingconstructorbreakpoints

Why is call to constructor not displayed when using "step into" in eclipse even without step filter


I'm trying to understand how Math.random() generates a random number. Therefore I used eclipse debugger and the feature "step into".

When I set a breakpoint at

        double mathRandom = Math.random();

And use "step into" this takes me into the Math.class to the code:

public static double random() {
    return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}

So calling random() calls constructor randomNumberGenerator in the class RandomNumberGeneratorHolder which is within the Math class.

The constructor randomNumberGenerator is also in the Math class in the line

private static final class RandomNumberGeneratorHolder {
    static final Random randomNumberGenerator = new Random();
}

But when I use "step into" in the line

public static double random() {
    return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}

Why does this not take me to the constructor

private static final class RandomNumberGeneratorHolder {
    static final Random randomNumberGenerator = new Random();
}

But instead takes me into the Random class to the line

public double nextDouble() {
    return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}

I have "Use step filters" disabled. So what is the reason eclipse skips the call to the constructor

static final Random randomNumberGenerator = new Random()

Solution

  • With Math.random() you call a static method. Static methods do not depend on having an instance of the class.

    A non-static call would be:

    Math math=new Math();
    double m = math.random();
    

    But that does not compile because the default constructor of Math is private.

    You wrote "So calling random() calls constructor randomNumberGenerator in the class", which is not true. There is no "new" keyword, hence no constructor call.

    RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
    

    Here "randomNumberGenerator" is a static attribute (variable) of the RandomNumberGeneratorHolder class. Static access does not depend on calling a constructor.

    Java classes may optionally contain a nameless static initializer which is executed by the Java VM when the class gets loaded into memory. Static initializer can initialize static attributes of the class. Such an initializer did obviously fill the static "randomNumberGenerator" attribute with an instance of a class. Therefore you are able to call its non-static nextDouble() method.

    Other well known examples are System.out and System.in.

    I give you two examples how to program such a static initializer:

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    class Main
    {
        static List<String> names;    
        static List<String> colors= Arrays.asList("red","green");
    
        static // notice that this method has no name!
        {
            names=new ArrayList<String>();
            names.add("CuriousIndeed");
            names.add("Stefan");
        }
    
        public static void main(String[] args)
        {
            System.out.println(names);
            System.out.println(colors);
        }
    }
    

    Outputs:

    [CuriousIndeed, Stefan]
    [red, green]
    

    Both, the names and colors have been statically initialized but in two different ways.