1

Say we have this class:

public class Chicken {
    public static final Chicken THE_FIRST_ONE = new Chicken("Little");
    public static final Chicken THE_FIRST_EGG_1 = new Egg("Humpty-Dumpty");
    public static final Egg     THE_FIRST_EGG_2 = Egg.THE_FIRST_ONE;
    protected String _name;
    public Chicken(String name) {
        _name = name;
    }
    public String toString() {
        return "Chicken " + _name + "@" + System.identityHashCode(this);
    }
    public static void main(String args[]) {
        System.out.println("The first chicken was " + THE_FIRST_ONE);
        System.out.println("The first egg 1 was " + THE_FIRST_EGG_1);
        System.out.println("The first egg 2 was " + THE_FIRST_EGG_2);
        System.out.println("The first egg 3 was " + Egg.THE_FIRST_ONE);
    }
}

With

public class Egg extends Chicken {
    public static final Egg THE_FIRST_ONE = new Egg("Humpty-Dumpty");   
    public Egg(String name) {
        super(name);
    }
    public String toString() {
        return _name + " the egg" + "@" + System.identityHashCode(this);
    }
}

I think there is a problem with this. But I cannot reproduce the problem. In a more complicated scenario that's hard to boil down to something simple to post here, I get in some circumstances THE_FIRST_EGG_2 == null. And it's not during initialization but afterwards. In another case I get reflection not working properly.

This raises the question to me how this can even be possible?

How can we assign instances of a class during the class' static initialization? Aren't there circumstances where the class is not ready yet to be instantiated, and yet we require instances (object) to finish the static initialization of the class?

And what if we require an instance of a subclass which requires the super-class to be completely initialized so it can be fully initialized for instantiation. And then we are even asking the superclass to set final static fields to an instance of the subclass?

Like I said, I cannot reproduce any problem with my simple example here, but I have observed problems in a scenario like this and just from basic reasoning it seems like it should not even work at all like this. So it is a miracle that it does work.

I would like to know if there are any known anti-patterns surrounding this, any known problem that I should keep in mind when analyzing my code and verifying that it is correct (and fix what is obviously not correct)?

Not so fast with the closing. While it might be related to circular dependency, I cannot actually reproduce this problem here. BUT I do reproduce something else, surprisingly:

Now I am making things much simpler:

public interface Animal { }
public interface Cell { }

public class Chicken implements Animal {
    public static void main(String args[]) {
        Chicken chicken = new Chicken();
        System.out.println("chicken is an Animal? " + (chicken instanceof Animal));
        System.out.println("chicken interfaces: " + java.util.Arrays.asList(chicken.getClass().getInterfaces()));

        Egg egg = new Egg();
        System.out.println("egg is an Animal? " + (egg instanceof Animal));
        System.out.println("egg class interfaces: " + java.util.Arrays.asList(egg.getClass().getInterfaces()));
        System.out.println("egg's superclass interfaces: " + java.util.Arrays.asList(egg.getClass().getSuperclass().getInterfaces()));
    }
}

public class Egg extends Chicken implements Cell { }

The output is

chicken is an Animal? true
chicken interfaces: [interface Animal]
egg is an Animal? true
egg class interfaces: [interface Cell]
egg's superclass interfaces: [interface Animal]

The Class.getInterfaces() method does not return, as it's documentation says, "all interfaces implemented by the class". Because egg instanceof Animal is true, but Animal is not in the array of getInterfaces().

This is surprising. Normally there is a distinction made between getFields vs. getDeclaredFields. So getInterfaces would be expected to return really all implemented interfaces no matter where declared vs. getDeclaredInterfaces would be expected to only return the interfaces actually declared implemented on that class itself.

Gunther Schadow
  • 1,490
  • 13
  • 22

0 Answers0