枚举的参数始终设置为null

时间:2019-12-11 00:31:18

标签: java oop enums game-development

我有两个类,FruitPlant和Fruit,每个类都有自己的Type枚举。他们在这里:

public class FruitPlant extends Plant {
    public static enum Type {
        // Dry-hot 
        PEACH_TREE("peach", 3, 80, Fruit.Type.PEACH),
        CACTUS("cactus", 10000, 120, Fruit.Type.PRICKLYPEAR), 

        // Dry-cool
        BLUEBERRY_BUSH("blueberry", 3, 40, Fruit.Type.BLUEBERRY),
        CHERRY_TREE("cherry", 3, 60, Fruit.Type.CHERRY), 

        // Wet-hot
        ORANGE_TREE("orange", 2, 80, Fruit.Type.ORANGE),
        MELON_VINE("melon", 1.5, 80, Fruit.Type.MELON), 

        // Wet-cool
        APPLE_TREE("apple", 2, 60, Fruit.Type.APPLE), 
        STRAWBERRY_BUSH("strawberry", 1.5, 60, Fruit.Type.STRAWBERRY);

        public double waterHardiness;
        public int preferedTemp;
        public int[] babyImage;
        public int[] childImage;
        public int[] subAdultImage;
        public int[] adultImage;
        public int[] pregnantImage;
        public Fruit.Type fruitType;

        Type (String imagePath, double waterHardiness, int preferedTemp, Fruit.Type fruitType){
            this.waterHardiness = waterHardiness;
            this.preferedTemp = preferedTemp;
            babyImage = Image.loadImage("/res/plants/" + imagePath + "/baby.png");
            childImage = Image.loadImage("/res/plants/" + imagePath + "/child.png");
            subAdultImage = Image.loadImage("/res/plants/" + imagePath + "/subadult.png");
            adultImage = Image.loadImage("/res/plants/" + imagePath + "/adult.png");
            pregnantImage = Image.loadImage("/res/plants/" + imagePath + "/pregnant.png");
            this.fruitType = fruitType;
        }
    }

    Type type;
    public FruitPlant(Type type) {
        this.type = type;
        System.out.println(type.fruitType); // Prints whatever Fruit.Type the FruitPlant.Type has
    }
}
public class Fruit implements Element, Holdable, Plantable {
    public static enum Type {
        PRICKLYPEAR(FruitPlant.Type.CACTUS), 
        PEACH(FruitPlant.Type.PEACH_TREE),
        CHERRY(FruitPlant.Type.CHERRY_TREE), 
        BLUEBERRY(FruitPlant.Type.BLUEBERRY_BUSH),
        MELON(FruitPlant.Type.MELON_VINE), 
        ORANGE(FruitPlant.Type.ORANGE_TREE),
        APPLE(FruitPlant.Type.APPLE_TREE), 
        STRAWBERRY(FruitPlant.Type.STRAWBERRY_BUSH);


        public FruitPlant.Type plant;

        Type(FruitPlant.Type plant) {
            System.out.println(plant);
            this.plant = plant;
        }
    }

    Type type;
    public Fruit(Type type){
        this.type = type;
        System.out.println(type.plant); // Prints null
    }
}

以及一些必要的测试人员代码:

public class Main {
    public static void Main(String args[]){
        System.out.println("Next line printed should be BLUEBERRY:");
        FruitPlant blueberryBush = new FruitPlant(FruitPlant.Type.BLUEBERRY_BUSH);
        System.out.println("Next line printed should be BLUEBERRY_BUSH:");
        Fruit blueberry = new Fruit(Fruit.Type.BLUEBERRY);
        System.out.println("End test");

    }
}

每当我在FruitPlant构造函数中创建一个FruitPlant对象并将其传递给FruitPlant.Type枚举时,该枚举的fruit字段都会向我返回一个Fruit.Type枚举。但是,每当我在Fruit构造函数中创建一个Fruit对象并将其提供给Fruit.Type枚举时,该枚举的plant字段始终计算为null。

这与系统的循环性有关吗?为什么Fruit.Type.plant字段返回null,而FruitPlant.Type.fruit返回一个Fruit.Type枚举?在此先感谢!

PS:这两个课程还有更多,但由于它们无关紧要,因此我将其中的大部分内容删掉了。我还使用了带有类型枚举的骨架类,因为大多数果类植物和水果的行为类似,因此创建8个几乎相同的类是错误的。

1 个答案:

答案 0 :(得分:0)

之所以会出现此问题,是因为您有两个枚举Fruit.TypeFruitPlant.Type,它们都在它们的常量声明中互相引用:

public class FruitPlant extends Plant {
    public static enum Type {
        // Dry-hot 
        PEACH_TREE("peach", 3, 80, Fruit.Type.PEACH),
        // ...
    }
    // ...
}

// ...
public class Fruit implements Element, Holdable, Plantable {
    public static enum Type {
        // ...
        PEACH(FruitPlant.Type.PEACH_TREE),
        // ...
    }
    // ...
}

枚举常量Fruit.Type.PEACHFruitPlant.Type.PEACH_TREE必须先实例化才能使用。

假设PEACH首先被实例化;那么FruitPlant.Type.PEACH_TREE尚未实例化,因此该名称的静态成员的默认初始值为null。它要引用的对象尚不存在,因此无法对其进行引用。另一方面,如果首先实例化PEACH_TREE,则它无法获取对PEACH的引用,因为该对象尚不存在。当前将引用它的枚举成员的默认初始值为null

解决方案是延迟这些枚举之间的循环引用,直到所有枚举常量都已初始化为止。您可以编写方法getPlantgetFruit来返回正确的值,而不是将它们存储为字段。在调用这些方法时,所有枚举常量都将被实例化,因此不会有由于未初始化的成员而产生的默认null值。

public class FruitPlant extends Plant {
    public static enum Type {
        PEACH_TREE("peach", 3, 80),
        // ...

        public Fruit.Type getFruit() {
            switch(this) {
                case PEACH_TREE: return Fruit.Type.PEACH;
                // ...
                default: throw new IllegalStateException();
            }
        }

        // ...
    }
    // ...
}