简体   繁体   中英

Elements of ArrayList in Enum field Null. What is the correct way to do this?

My theory here is that the first enum upon initialization is forced to initialize the second enum first to build the first ArrayList, but when it builds the ArrayList of the second enum, rather than getting stuck in a logical loop, it sets the values to Null.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for (Ingredients ingredient: Ingredients.values()){
            Log.d("debug", ingredient.recipes.toString());
        }

        for (Recipes recipe: Recipes.values()){
            Log.d("debug",recipe.ingredients.toString());
        }
    }

    enum Ingredients {
        APPLE(new ArrayList<>(Arrays.asList(Recipes.APPLE_FRITTER))),
        BANANA(new ArrayList<>(Arrays.asList(Recipes.BANANA_FRITTER))),
        FLOUR(new ArrayList<>(Arrays.asList(Recipes.APPLE_FRITTER, Recipes.BANANA_FRITTER))),
        SUGAR(new ArrayList<>(Arrays.asList(Recipes.APPLE_FRITTER, Recipes.BANANA_FRITTER)));

        final ArrayList<Recipes> recipes;

        Ingredients(ArrayList<Recipes> products) {
            this.recipes = products;
        }
    }

    enum Recipes {
        APPLE_FRITTER(new ArrayList<>(Arrays.asList(Ingredients.APPLE, Ingredients.FLOUR, Ingredients.SUGAR))),
        BANANA_FRITTER(new ArrayList<>(Arrays.asList(Ingredients.BANANA, Ingredients.FLOUR, Ingredients.SUGAR)));

        final ArrayList<Ingredients> ingredients;

        Recipes(ArrayList<Ingredients> ingredients) {
            this.ingredients = ingredients;
        }
    }
}

Here is the logcat:

D/debug: [APPLE_FRITTER]
D/debug: [BANANA_FRITTER]
D/debug: [APPLE_FRITTER, BANANA_FRITTER]
D/debug: [APPLE_FRITTER, BANANA_FRITTER]
D/debug: [null, null, null]
D/debug: [null, null, null]

This code is sadly just a small example of a much larger project that depends on this working and if I need to effectively scrap everything and start over, just need some confirmation.

Of course of there is some trick here I am missing, that would be awesome. Thank you either way for your insight.

edit: Shortly after posting this, I think in response to admitting to defeat, I came up with what I thought was a brilliant refactor that would solve the issue. It didn't work but produced a different error. Sharing for those interested:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for (Ingredients ingredient: Ingredients.values()){
            Log.d("debug", ingredient.recipes.toString());
        }

        for (Recipes recipe: Recipes.values()){
            Log.d("debug",recipe.ingredients.toString());
        }
    }

    private final static ArrayList<Recipes> appleRecipes = new ArrayList<>(Arrays.asList(Recipes.APPLE_FRITTER));
    private final static ArrayList<Recipes> bananaRecipes = new ArrayList<>(Arrays.asList(Recipes.BANANA_FRITTER));
    private final static ArrayList<Recipes> flourRecipes = new ArrayList<>(Arrays.asList(Recipes.APPLE_FRITTER, Recipes.BANANA_FRITTER));
    private final static ArrayList<Recipes> sugarRecipes = new ArrayList<>(Arrays.asList(Recipes.APPLE_FRITTER, Recipes.BANANA_FRITTER));

    private final static ArrayList<Ingredients> appleFritterIngredients = new ArrayList<>(Arrays.asList(Ingredients.APPLE, Ingredients.FLOUR, Ingredients.SUGAR));
    private final static ArrayList<Ingredients> bananaFritterIngredients = new ArrayList<>(Arrays.asList(Ingredients.BANANA, Ingredients.FLOUR, Ingredients.SUGAR));

    enum Ingredients {
        APPLE(appleRecipes),
        BANANA(bananaRecipes),
        FLOUR(flourRecipes),
        SUGAR(sugarRecipes);

        final ArrayList<Recipes> recipes;

        Ingredients(ArrayList<Recipes> products) {
            this.recipes = products;
        }
    }

    enum Recipes {
        APPLE_FRITTER(appleFritterIngredients),
        BANANA_FRITTER(bananaFritterIngredients);

        final ArrayList<Ingredients> ingredients;

        Recipes(ArrayList<Ingredients> ingredients) {
            this.ingredients = ingredients;
        }
    }
}

And relevent logcat:

D/debug: [APPLE_FRITTER]
D/debug: [BANANA_FRITTER]
D/debug: [APPLE_FRITTER, BANANA_FRITTER]
D/debug: [APPLE_FRITTER, BANANA_FRITTER]
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.util.ArrayList.toString()' on a null object reference

The problem is that you have two enums referencing each other in their constructors , this is a circular reference. You can solve this with setter initialization.

Free tip: Arrays.asList returns a new ArrayList , so you don't need to wrap it again in a new ArrayList . =)

enum Ingredients {
    APPLE,
    BANANA,
    FLOUR,
    SUGAR;

    static{
        APPLE.setRecipes(Arrays.asList(Recipes.APPLE_FRITTER));
        BANANA.setRecipes(Arrays.asList(Recipes.BANANA_FRITTER));
        FLOUR.setRecipes(Arrays.asList(Recipes.APPLE_FRITTER, Recipes.BANANA_FRITTER));
        SUGAR.setRecipes(Arrays.asList(Recipes.APPLE_FRITTER, Recipes.BANANA_FRITTER));
    }

    List<Recipes> recipes;

    private void setRecipes(List<Recipes> products){
        this.recipes = products;
    }

}

enum Recipes {
    APPLE_FRITTER,
    BANANA_FRITTER;

    static{
        APPLE_FRITTER.setIngredients(Arrays.asList(Ingredients.APPLE, Ingredients.FLOUR, Ingredients.SUGAR));
        BANANA_FRITTER.setIngredients(Arrays.asList(Ingredients.BANANA, Ingredients.FLOUR, Ingredients.SUGAR));
    }

    List<Ingredients> ingredients;

    private void setIngredients(List<Ingredients> ingredients) {
        this.ingredients = ingredients;
    }

}

The Java Classloader is a part of the JRE that dynamically loads Java classes into the JVM. Usually classes are only loaded on demand.

When the JVM starts classloading Ingredients . It sees the Recipes.APPLE_FRITTER in Ingredients.APPLE 's constructor, so it starts classloading Recipes . It sees Ingredients.APPLE , Ingredients.FLOUR and Ingredients.SUGAR references in Recipes.APPLE_FRITTER 's constructor, but we are still in Ingredients.APPLE 's constructor, so Ingredients.APPLE , Ingredients.FLOUR and Ingredients.SUGAR are null at this point, so Recipes.APPLE_FRITTER 's constructor gets all items as null.

Sorry for the bad english. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM