Polyfant
Polyfant

Reputation: 38

Java outer class static initialization

I have a problem with Java static initialization. What I want to do is some type checking with generic constants and to translate between types and type names. So I have some typed constants in interface MC and a hash map in inner class Type to translate names to types. Now when I call

MC.Type.getValue("MInteger")
the inner class Type is initialized but not the static constants in the outer class MC so the return value is null. How can I get Java to initialize these constants? I could do

static { Type<?> dummy = MC.MBoolean; }

in class Type but isn't there some better way to do this. Or am I doing this totally wrong.

import java.util.HashMap;
import java.util.Map;

interface MC {
    public static final Type<Boolean> MBoolean = new Type<>("MBoolean");
    public static final Type<Integer> MInteger = new Type<>("MInteger");

    public static class Type<T> {
        private static final Map<String, Type<?>> types = new HashMap<>();
        private final String name;

        private Type(String name) {
            this.name = name;
            types.put(name, this);
        }

        public String getName() {
            return name;
        }

        public static Type<?> getValue(String name) {
            return types.get(name);
        }
    }
}

public class Main {

    public static void main(String[] args) {
        System.out.println(MC.Type.getValue("MInteger"));
        MC.MBoolean.getName();
        System.out.println(MC.Type.getValue("MInteger"));
    }
}

Upvotes: 1

Views: 126

Answers (3)

Vaisakh PS
Vaisakh PS

Reputation: 1201

The Constructor won't initialize unless you explicitly call MC.MBoolean. so better you go with the Double brace initialization.

private static final Map<String, Type<?>> types = new HashMap<>() {
            {
                put(MC.MBoolean.getName(), MC.MBoolean);
                put(MC.MInteger.getName(), MC.MInteger);
            }
        };

Upvotes: 0

user4413257
user4413257

Reputation:

You can use either static initializer block:

private static final Map<String, Type<?>> types = new HashMap<>();

static {
    types.put(MC.MBoolean.getName(), MC.MBoolean);
    types.put(MC.MInteger.getName(), MC.MInteger);
}

or double brace initialization:

private static final Map<String, Type<?>> types = new HashMap<>() {{
    put(MC.MBoolean.getName(), MC.MBoolean);
    put(MC.MInteger.getName(), MC.MInteger);
}};

First curly braces creates new anonymous subclass of HashMap, second curly braces are instance initializer block which is executed at construction time (arg-less constructor for anonymous classes).

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

Since all Type instances are included in your MC class, a very direct approach to solving this problem would be to move registration of the class with the Type.types map from the constructor of Type to its static initializer:

private static final Map<String, Type<?>> types = new HashMap<>();
static {
    types.put(MBoolean.getName(), MBoolean);
    types.put(MInteger.getName(), MInteger);
}
private Type(String name) {
    this.name = name;
    // removed types.put(name, this); from here
}

Demo.

Upvotes: 1

Related Questions