我正在试着做一些像Desmos这样的东西。我成功地让它绘制了一些基本的函数,如e^x,sin (x),x^2,1/x等。问题是当我试图用另一个函数作为参数来绘制一个函数时。例如,我尝试绘制sin (2x),它显示了前面提到的错误Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
。
我试着做了很多事情,但都没有奏效。以下是这里使用的代码部分:(其中一些是塞尔维亚语,但我将翻译必要的部分):
来自主类的
public static void main(String[] args)
{
/*...*/
Funkcija f1 = new LinearnaFunkcija(2, 0);
Funkcija f = new SinFunkcija();
/*...*/
}
从Funkcija
(function)类
public Double vrednost(Double arg)
{
if(arg.isNaN() || arg == null || arg.isInfinite())
{
return Double.NaN;
}
if (this.arg.equals(new LinearnaFunkcija(1,0)))
{
this.arg = null;
}
return vrednost(this.arg.vrednost(arg));
}
注意:"vrednost“表示"value”
来自LinearnaFunkcija
(线性函数)类
public class LinearnaFunkcija extends Funkcija
{
private double k;
private double n;
public LinearnaFunkcija(double k, double n)
{
this.k = k;
this.n = n;
}
public LinearnaFunkcija(double arg)
{
this.k = 0;
this.n = arg;
}
public Double vrednost(Double arg)
{
if(this.arg != null)
{
super.vrednost(arg);
}
return k * arg + n;
}
/*...*/
}
来自SinFunkcija
(正弦函数)类
public Double vrednost(Double arg)
{
if(this.arg != null)
{
super.vrednost(arg);
}
return Math.sin(arg);
}
绘制函数的方法
public void draw(Graphics g)
{
/*...*/
Double xc, yc;
int xp;
int[] x = new int[1000010];
int[] y = new int[1000010];
int count = 0;
for(xp = 0; xp < polje.getWidth(); xp++, count++)
{
xc = polje.getXValue(xp);
yc = f.vrednost(xc);
if(yc.isNaN() || yc.isInfinite() || polje.getYPos(yc) < 0)
{
g.drawPolyline(x, y, count);
count = -1;
continue;
}
x[count] = xp;
y[count] = polje.getYPos(yc);
}
g.drawPolyline(x, y, count);
}
}
(注意:polje
是JPanel
子类的一个实例)
所以当我运行这段代码时,我会得到
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.newLine(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at funkcije.LinearnaFunkcija.vrednost(LinearnaFunkcija.java:26)
at funkcije.Funkcija.vrednost(Funkcija.java:30)
at funkcije.SinFunkcija.vrednost(SinFunkcija.java:42)
at funkcije.Funkcija.vrednost(Funkcija.java:30)
at funkcije.SinFunkcija.vrednost(SinFunkcija.java:42)
at funkcije.Funkcija.vrednost(Funkcija.java:30)
at funkcije.SinFunkcija.vrednost(SinFunkcija.java:42)
at funkcije.Funkcija.vrednost(Funkcija.java:30)
at funkcije.SinFunkcija.vrednost(SinFunkcija.java:42)
at funkcije.Funkcija.vrednost(Funkcija.java:30)
,等等。
将显示窗口(JFrame
),但该窗口为空白。
有人知道是什么导致了这个问题吗?根据错误,这两个方法显然是递归地相互调用,这将造成一个永无止境的堆栈,即堆栈溢出。但这是不应该发生的。其他人知道问题出在哪里吗?
如果你需要更多的代码,请告诉我。
发布于 2018-06-15 04:00:29
让我为Function
推荐一个更好的设计,在这个设计中可以避免递归调用和对super
的调用。如果实际的计算逻辑(例如,用于SinFunkcija
的return Math.sin(arg)
,用于LinearnaFunkcija
的k * arg + n
等)与处理特殊情况和嵌套函数调用是分开的。
其中一种方法是应用模板方法模式,如下所示:
public abstract class Function {
private final Function nested;
public Function(Function nested) {
this.nested = nested; //a nested function, possibly null
}
public void calculate(Double argument) {
if (this.nested != null) { //first, try calculating the inner function
argument = this.nested.calculate(argument);
}
if (argument == null || argument.isNaN() || argument.isInfinite()) { //then, check if argument is valid; be careful to check argument == null before you try and invoke methods on it!
return Double.NaN;
}
return calculateForValidValue(argument); //at this point, you're 100% sure arg is a valid Double
}
protected abstract Double calculateForValidValue(Double argument);
}
然后,子类变成:
public class SinFunkcija extends Function {
protected Double calculateForValidValue(Double argument) {
return Math.sin(argument); //as simple as that
}
}
您可以通过嵌套构造函数调用来嵌套函数:new SinFunkcija(new LinearnaFunkcija(null, 2, 0)).calculate(3.0)
。
注意,‘最里面’函数的参数是简单的null
。如果您想要使用空对象模式(我认为这就是this.arg.equals(new LinearnaFunkcija(1,0))
代码行的内容),您可以使用一个特殊的Noop
函数:
public class Noop extends Function {
public Noop() {
super(null); //no nested function here
}
//this is the only case when we want to override calculate
public void calculate(Double argument) {
return argument;
}
protected Double calculateForValidValue(Double value) { return null; }
}
然后,您可以编写像这样的函数:new SinFunkcija(new LinearnaFunkcija(new Noop(), 2, 0)).calculate(3.0)
,并跳过Function
中的if (this.nested != null) {
检查。
https://stackoverflow.com/questions/50863927
复制相似问题