public class StaticVsInstance {
    static int created = 0;          // one copy, shared by every object
    final int id;                    // one copy per object

    StaticVsInstance() { id = ++created; }

    static String describe() { return "created so far: " + created; }

    class Inner {                    // needs an enclosing instance
        String owner() { return "inner of #" + id; }
    }
    static class Nested {            // does not
        String owner() { return "nested, no enclosing object, created=" + created; }
    }

    public static void main(String[] args) {
        StaticVsInstance a = new StaticVsInstance();
        StaticVsInstance b = new StaticVsInstance();
        System.out.println("a.id=" + a.id + " b.id=" + b.id + " " + describe());

        StaticVsInstance.Inner in = b.new Inner();
        System.out.println(in.owner());
        System.out.println(new Nested().owner());

        // reaching a static member through an instance compiles but is misleading
        StaticVsInstance nothing = null;
        System.out.println("static via null reference: " + nothing.created);

        System.out.println("fields in Inner: " + java.util.Arrays.toString(Inner.class.getDeclaredFields()));
        System.out.println("fields in Nested: " + java.util.Arrays.toString(Nested.class.getDeclaredFields()));
    }
}
