【问题标题】:How to fill randomly chosen object of class with random generated parameters?如何用随机生成的参数填充随机选择的类对象?
【发布时间】:2013-12-29 20:46:11
【问题描述】:

我必须将我的代码更改为从使用反射到生成随机参数的解决方案。

我不知道如何实现这个...

这是类生成器:

public class SweetsGenerator implements Generator<Sweets>, Iterable<Sweets> {

    private static final Logger LOG = Logger.getLogger(SweetsGenerator.class);

    @SuppressWarnings("rawtypes")
    private Class[] types = { 
        WhiteChocolate.class, MilkChokolate.class,  DarkChocolate.class, 
        DesertChocolate.class, PorousChocolate.class, 
    };

    private static Random rand = new Random();

    public SweetsGenerator() {
    }

    private int size = 0;

    public SweetsGenerator(int sz) {
        size = sz;
    }

    public Sweets next() {
        try {
            return (Sweets) types[rand.nextInt(types.length)].newInstance();
        } catch (Exception e) {
            LOG.error("RuntimeException", e);
            throw new RuntimeException(e);
        }
    }

    class SweetsIterator implements Iterator<Sweets> {
        int count = size;

        public boolean hasNext() {
            return count > 0;
        }

        public Sweets next() {
            count--;
            return SweetsGenerator.this.next();
        }

        public void remove() { // Not implemented
            LOG.error("UnsupportedOperationException");
            throw new UnsupportedOperationException();
        }
    };

    public Iterator<Sweets> iterator() {
        return new SweetsIterator();
    }
}

如何规避这种方法并创建新的类元素,例如:

新白巧克力((rand.nextDouble() * 100) + 1, (rand.nextDouble() * 200) + 1);

我不能将它与我们可以创建的随机生成类女巫元素结合起来。

这是Sweets抽象类的内容和其中一个实现:

public abstract class Sweets {

    private double sugarLevel;

    private double weight;

    public double getSugarLevel() {
        return sugarLevel;
    }

    public double getWeight() {
        return weight;
    }

    public void setSugarLevel(double sugarLevel) {
        this.sugarLevel = sugarLevel;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName() + " " + sugarLevel + " " + weight);
        return sb.toString();
    }   
}

public class Chocolate extends Sweets {

    public Chocolate() {
    }

    public Chocolate(double aSugarLevel, double aWeight) {
        setSugarLevel(aSugarLevel);
        setWeight(aWeight);
    }
}

更新:

我尝试通过 skiwi 的建议修改 next()

下一个更改版本:

public Sweets next() {
    Sweets current = instances[rand.nextInt(instances.length)];
    Double param1 = (rand.nextDouble() * 100) + 1;
    Double param2 = (rand.nextDouble() * 200) + 1;
    System.out.println("parameters: " + Math.round(param1) + " " + Math.round(param2));

    try {
        return (Sweets) current.getClass()
                .getConstructor(Double.class, Double.class)
                .newInstance(Math.round(param1), Math.round(param2));
        // Report programmer errors at run time:
    } catch (Exception e) {
        LOG.error("RuntimeException", e);
        throw new RuntimeException(e);
    }
}

但它会引发下一堆异常:

23:25:51,337 ERROR main SweetsGenerator:next:52 - RuntimeException
 java.lang.NoSuchMethodException: com.epam.lab.chocolate.DarkChocolate.<init>(java.lang.Double, java.lang.Double)
    at java.lang.Class.getConstructor0(Class.java:2800)
    at java.lang.Class.getConstructor(Class.java:1708)
    at com.epam.lab.SweetsGenerator.next(SweetsGenerator.java:48)
    at com.epam.lab.NewYearGift.generate(NewYearGift.java:37)
    at com.epam.lab.GiftList.generateGift(GiftList.java:47)
    at com.epam.lab.GiftList.main(GiftList.java:59)
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodException: com.epam.lab.chocolate.DarkChocolate.<init>(java.lang.Double, java.lang.Double)
    at com.epam.lab.SweetsGenerator.next(SweetsGenerator.java:53)
    at com.epam.lab.NewYearGift.generate(NewYearGift.java:37)
    at com.epam.lab.GiftList.generateGift(GiftList.java:47)
    at com.epam.lab.GiftList.main(GiftList.java:59)
Caused by: java.lang.NoSuchMethodException: com.epam.lab.chocolate.DarkChocolate.<init>(java.lang.Double, java.lang.Double)
    at java.lang.Class.getConstructor0(Class.java:2800)
    at java.lang.Class.getConstructor(Class.java:1708)
    at com.epam.lab.SweetsGenerator.next(SweetsGenerator.java:48)
    ... 3 more

这个问题的解决方法是改一行:

return (Sweets) current.getClass().getConstructor(double.class, double.class) .newInstance(Math.round(param1), Math.round(param2));

如何保护这个生成器的逻辑并随机创建带参数的元素?

有什么建议吗?

【问题讨论】:

    标签: java random generator


    【解决方案1】:

    如果你有像public WhiteChololate(Double a, Double b)这样的构造函数契约,你可以调用下面的方法来创建一个新的实例:

    Double a = 1d;
    Double b = 2d;
    WhiteChocolate.class.getConstructor(Double.class, Double.class).newInstance(a, b);
    

    这将构造所需的实例,而不是我在Class&lt;?&gt;.newInstance() 上使用此语法,因为正如here 所述:

    请注意,此方法会传播由 nullary 构造函数引发的任何异常,包括已检查的异常。使用此方法可以有效地绕过编译器执行的编译时异常检查。 Constructor.newInstance 方法通过将构造函数抛出的任何异常包装在(已检查的)InvocationTargetException 中来避免此问题。

    所以使用Constructor.newInstance(...) 既更安全,也是唯一能满足您需求的。

    请注意,您需要在.getConstructor() 调用中指定参数type,而不是值。

    【讨论】:

    • @nazar_art 您的DarkChocolate 没有采用Double, Double 的构造函数。所有类都需要采用该构造函数,否则您需要在生成器的next() 中做出一些区分。
    • 解决方案改为getConstructor(double.class, double.class)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-13
    • 2018-04-03
    • 2011-01-17
    • 2015-12-02
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多