java - 二维数组中的 NullPointerException

标签 java arrays swing nullpointerexception

我编写了这段代码(独立的),它抛出了一个让我感到困惑的 NPE。它涉及模型中使用的 Ray 对象的二维数组。 Ray 对象被初始化并设置为模型。当模型外部需要它们时,代码会调用 model.getRays()。那时代码迭代二维数组并记录每个对象,因为......代码调用 getRays() 后仅仅 2-3 行,二维数组的第一个元素是 null !

没有线程发生可能会干扰数组中的对象,因此我很困惑它们如何在测试它们包含有效对象后不久才为 null

这段代码有什么问题,我该如何解决?

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.util.logging.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class TestNullOn2DArray {

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                GUI gui = new GUI();

                JFrame f = new JFrame("Test Null On 2D Array");
                f.add(gui.getContainer());
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setLocationByPlatform(true);

                f.pack();
                f.setMinimumSize(f.getSize());
                f.setVisible(true);
                gui.plot();
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

class GUI {

    Logger log = Logger.getAnonymousLogger();
    private JPanel container;
    JLabel output;
    private JMenuBar menuBar;
    private BufferedImage canvas;
    private CustomModel model =
            new CustomModel(5, 1, .66f);
    private int defaultPositionNumber = 5;
    private int defaultAngleNumber = 5;

    public void plot() {
        Ray[][] rays = model.getRays();
        log.log(Level.INFO, "Rays: " + rays);
        for (int ii = 0; ii < rays.length; ii++) {
            for (int jj = 0; jj < rays[ii].length; jj++) {
                Ray ray = rays[ii][jj];
                log.log(Level.INFO, "Ray: " + ray);
                ray.resolve();
            }
        }
    }

    public JPanel getContainer() {
        if (container == null) {
            container = new JPanel(new BorderLayout(5, 5));
            container.setBorder(new EmptyBorder(4, 4, 4, 4));

            ImageIcon icon = new ImageIcon(getCanvas());
            output = new JLabel(icon);
            container.add(new JScrollPane(output), BorderLayout.CENTER);
        }
        return container;
    }

    public void refreshCanvas() {
        model = new CustomModel(5, 6, .66f);
        canvas = null;
        BufferedImage bi = getCanvas();
        output.setIcon(new ImageIcon(bi));
    }

    public void initializeRays(Graphics2D g) {
        log.log(Level.INFO, "initializeRays()");

        int startAngle = 1;
        int numberAngles = defaultAngleNumber;
        int inc = 90 / numberAngles;
        int numberPositions = defaultPositionNumber;
        Ray[][] rays = new Ray[numberAngles][numberPositions];
        g.setTransform(AffineTransform.getTranslateInstance(0d, 0d));
        for (int ii = rays.length - 1; ii > 0; ii--) {
            for (int jj = 0; jj < rays[0].length; jj++) {
                GeneralPath gp = new GeneralPath();

                double rads = 2d * Math.PI * (startAngle + (inc * ii)) / 360d;
                double x = 400d;
                double y = 100d;
                double yStart = y - (Math.sin(rads) * 100d);
                double xStart = x + (Math.cos(rads) * 100d);
                float r = 2f * (float) ((rads / Math.PI));
                float b = (float) jj / (float) rays[0].length;
                Color color = new Color(r, 1 - r, b, .6f);
                g.setColor(color);
                g.drawLine((int) x, (int) y, (int) xStart, (int) yStart);
                gp.moveTo(xStart, yStart);
                gp.lineTo(x, y);
                gp.closePath();
                Ray ray = new Ray(gp, color);
                log.log(Level.INFO, "" + ray);
                rays[ii][jj] = ray;
            }
        }
        model.setRays(rays);
        if (output != null) {
            output.repaint();
        }
    }

    public BufferedImage getCanvas() {
        if (canvas == null) {
            Dimension size = model.getPreferredSize();
            int w = size.width;
            int h = size.height;
            canvas = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = canvas.createGraphics();

            g.setColor(Color.WHITE);
            g.fillRect(0, 0, w, h);
            g.setColor(new Color(125, 27, 155, 127));

            initializeRays(g);

            g.dispose();
        }
        return canvas;
    }
}

class CustomModel {

    private int width;
    private int layers;
    private float offset;
    private Ray[][] rays;
    private Logger log = Logger.getAnonymousLogger();

    public CustomModel(int width, int layers, float offset) {
        this.width = width;
        this.layers = layers;
        this.offset = offset;
    }

    public Line2D.Double getLineOfLasSegment() {
        Line2D.Double line = new Line2D.Double(0d, 0d, 1d, 1d);
        return line;
    }

    public Dimension getPreferredSize() {
        int w = 600;
        int h = 300;
        Dimension prefSize = new Dimension(w, h);
        return prefSize;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getLayers() {
        return layers;
    }

    public void setLayers(int layers) {
        this.layers = layers;
    }

    public Ray[][] getRays() {
        for (int ii = 0; ii < rays.length; ii++) {
            for (int jj = 0; jj < rays[ii].length; jj++) {
                log.log(Level.INFO, "Ray: " + this.rays[ii][jj]);
            }
        }
        return rays;
    }

    public void setRays(Ray[][] rays) {
        this.rays = rays;
        for (int ii = 0; ii < rays.length; ii++) {
            for (int jj = 0; jj < rays[ii].length; jj++) {
                //Ray ray = rays[ii][jj];
                this.rays[ii][jj] = rays[ii][jj];
                log.log(Level.INFO, "Ray: " + this.rays[ii][jj]);
            }
        }
    }

    public float getOffset() {
        return offset;
    }

    public void setOffset(float offset) {
        this.offset = offset;
    }
}

class Ray {

    private final Logger logger = Logger.getAnonymousLogger();
    private GeneralPath path;
    private boolean started = false;
    private Color color;

    Ray(GeneralPath path, Color color) {
        this.path = path;
        this.color = color;
    }

    public void resolve() {
        logger.log(Level.INFO, "..resolving.");
    }

    public GeneralPath getPath() {
        return path;
    }

    public boolean isStarted() {
        return started;
    }

    @Override
    public String toString() {
        String s = "Ray: "
                + "  started=" + started;
        return s;
    }
}

输出

这显示了输出的最后一部分,检查 getRays() 将返回什么,然后是 NPE。

// ...
Jun 29, 2013 4:56:55 PM CustomModel getRays
INFO: Ray: Ray:   started=false
Jun 29, 2013 4:56:55 PM GUI plot
INFO: Rays: [[LRay;@1a9876e
Jun 29, 2013 4:56:55 PM GUI plot
INFO: Ray: null
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at GUI.plot(TestNullOn2DArray.java:52)
        at TestNullOn2DArray$1.run(TestNullOn2DArray.java:26)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:727)
        at java.awt.EventQueue.access$200(EventQueue.java:103)
        at java.awt.EventQueue$3.run(EventQueue.java:688)
        at java.awt.EventQueue$3.run(EventQueue.java:686)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:697)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
...

最佳答案

通过我的调试器查看它,看起来 ray[0] 中的所有内容都是空的。所有else 都存在。

因此,通过跟踪挖掘,我相信首先找到了将数据放在那里的原因,以及第一行为空的原因:

  1. 我们调用 f.add(gui.getContainer());。这本身似乎无害,但让我们看看 getContainer 正在做什么......

  2. 我们实例化 ImageIcon icon = new ImageIcon(getCanvas());。再次,无害,但让我们再次进入兔子洞......

  3. 然后我们在 getCanvas() 中调用(最后)initializeRays(g);!这里出了什么问题? 这个: for (int ii = rays.length - 1; ii > 0; ii--)

好的,您正在倒数。很奇怪,只有在极少数情况下才应该这样做,但我想你有你的理由。但是,倒数有两个问题:

  • 您需要从长度 n-1 开始,您就是这样做的;和
  • 您的循环条件必须大于或等于 0。您有那个条件。

将其更改为包含大于或等于测试,您将不会再有任何 NPE。

关于java - 二维数组中的 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17377641/

相关文章:

java - Java 8 数组构造函数引用如何工作?

java - 如何在特定位置放置组件?

java - 面对行动执行的问题

java - 多模块 hibernate 应用程序

java - 获取 JFrame 内容的实际大小

java - 从 Alfresco 集成测试上下文访问 Spring bean

javascript - JavaScript 数组是否有类似于 forEach 的可链接方法?

python - 从 3D numpy 数组中选择多个补丁

java - JFrame 在 thread.sleep() 之前未更新

java - 连接队列