【问题标题】:Randomly passing null references into objects将空引用随机传递给对象
【发布时间】:2016-01-25 14:10:20
【问题描述】:

我创建了一个程序,该程序应显示一艘宇宙飞船(基本上是两个矩形),并在每次按下空格键时从其中发射一颗子弹。但它不起作用,因为显然,我的程序将一个空的 Ship 引用传递给我的其他类之一,即 MoveAction 类。我完全不知道为什么会这样,因为在我的 Main 类中,我在 Shoot 类之前实例化了我的 Ship 对象(调用构造函数使用 ship 对象)。如果这个问题有点傻,我很抱歉,因为我仍然是一个新手程序员,不知道他大部分时间在做什么:) 这是我的代码:

public enum Direction {
    LEFT, RIGHT, SPACE
}

import javax.swing.JFrame;

public class Main {
    public static void main(String[] args) {
        JFrame frame;

        Ship s1;
        Shoot shoot;

        // Set the frame up
        frame = new JFrame();
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setVisible(true);

        // Get some more necessary objects
        s1 = new Ship();
        shoot = new Shoot(s1);
        frame.getContentPane().add(shoot);
        s1.setShoot(shoot);

        // Threads
        Thread ship = new Thread(s1);
        ship.start();
    }
}

import java.awt.Graphics;
import java.awt.event.KeyEvent;

import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

public class Shoot extends JPanel {

    Ship s1;

    public Shoot(Ship s1) {
        this.s1 = s1;

        addKeyBinding(KeyEvent.VK_LEFT, "left.pressed", new MoveAction(true, s1, Direction.LEFT), true);
        addKeyBinding(KeyEvent.VK_LEFT, "left.released", new MoveAction(false, s1, Direction.LEFT), false);

        addKeyBinding(KeyEvent.VK_RIGHT, "right.pressed", new MoveAction(true, s1, Direction.RIGHT), true);
        addKeyBinding(KeyEvent.VK_RIGHT, "right.released", new MoveAction(false, s1, Direction.RIGHT), false);

        addKeyBinding(KeyEvent.VK_SPACE, "space.pressed", new MoveAction(true, s1, Direction.SPACE), true);
        addKeyBinding(KeyEvent.VK_SPACE, "space.released", new MoveAction(false, s1, Direction.SPACE), false);

        setDoubleBuffered(true);
    }

    @Override
    public void paintComponent(Graphics g) {
        // Draw the ship
        super.paintComponent(g);
        s1.draw(g);
        g.fill3DRect(40, 50, 10, 10, false);
    }

    protected void addKeyBinding(int keyCode, String name, Action action, boolean keyPressed) {
        if (keyPressed) {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, false), name, action);
        } else {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, true), name, action);
        }
    }

    protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
        InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = getActionMap();
        inputMap.put(keyStroke, name);
        actionMap.put(name, action);
    }

}

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

public class Ship implements Runnable {
    int x, y, xDirection, bx, by;
    boolean readyToFire, shooting = false;
    Rectangle bullet;
    Shoot shoot;

    public Ship() {
        x = 175;
        y = 275;
        bullet = new Rectangle(0, 0, 3, 5);
    }

    public void draw(Graphics g) {
        // System.out.println("draw() called");
        g.setColor(Color.BLUE);
        g.fillRect(x, y, 40, 10);
        g.fillRect(x + 18, y - 7, 4, 7);
        if (shooting) {
            g.setColor(Color.RED);
            g.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
        }
        shoot.repaint();
    }

    public void move() {
        x += xDirection;
        if (x <= 0)
            x = 0;
        if (x >= 360)
            x = 360;
        shoot.repaint();
    }

    public void shoot() {
        if (shooting) {
            bullet.y--;
            shoot.repaint();
        }
    }

    public void setXDirection(int xdir) {
        xDirection = xdir;
    }

    public void setShoot(Shoot shoot) {
        this.shoot = shoot;
    }

    @Override
    public void run() {
        try {
            while (true) {
                shoot();
                move();
                Thread.sleep(5);
            }
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }

    }
}

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.util.HashSet;

import javax.swing.AbstractAction;

public class MoveAction extends AbstractAction {

    boolean pressed;
    Ship s1;
    Direction dir;
    private HashSet<Direction> movement;

    public MoveAction(boolean pressed, Ship s1, Direction dir) {
        System.out.println("moveaction class");
        this.pressed = pressed;
        this.s1 = s1;
        this.dir = dir;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            if (movement.contains(Direction.LEFT)) {
                if (pressed) {
                    s1.setXDirection(-1);
                } else {
                    s1.setXDirection(0);
                }
            } else if (movement.contains(Direction.RIGHT)) {
                if (pressed) {
                    s1.setXDirection(1);
                } else {
                    s1.setXDirection(0);
                }
            } else if (movement.contains(Direction.SPACE)) {
                if (pressed) {
                    if (s1.bullet == null)
                        s1.readyToFire = true;
                    if (s1.readyToFire) {
                        s1.bullet.x = s1.x + 18;
                        s1.bullet.y = s1.y - 7;
                        s1.shooting = true;
                    }
                } else {
                    s1.readyToFire = false;
                    if (s1.bullet.y <= -7) {
                        s1.bullet = null;
                        s1.shooting = false;
                        s1.bullet = null;
                        s1.bullet = new Rectangle(0, 0, 0, 0);
                        s1.readyToFire = true;
                    }
                }
            }
        } catch (NullPointerException ex) {
            System.out.println("NullPointerException");
        }
    }

堆栈跟踪:)

at MoveAction.actionPerformed(MoveAction.java:24)
    at javax.swing.SwingUtilities.notifyAction(Unknown Source)
    at javax.swing.JComponent.processKeyBinding(Unknown Source)
    at javax.swing.KeyboardManager.fireBinding(Unknown Source)
    at javax.swing.KeyboardManager.fireKeyboardAction(Unknown Source)
    at javax.swing.JComponent.processKeyBindingsForAllComponents(Unknown Source)
    at javax.swing.SwingUtilities.processKeyBindings(Unknown Source)
    at javax.swing.UIManager$2.postProcessKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

【问题讨论】:

  • "寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定问题或错误以及在问题本身中重现它所需的最短代码。没有明确的问题陈述对其他读者没有用处。”
  • 另外,给定标签:stackoverflow.com/questions/218384/…的可能重复
  • 还有一个堆栈跟踪会很好:) 我不知道 nullpointer 出现在哪里
  • 我已将您的代码复制到本地项目中进行测试。窗口打开,但不显示任何内容。除此之外,我没有得到任何 NPE。正如您在问题中所述,您在 Main 中实例化 Ship:s1 = new Ship();;将其传递给 Shoot 实例:shoot = new Shoot(s1);;并在 Shoot-constructor 中使用它:this.s1 = s1; ... new MoveAction(true, s1, Direction.LEFT) ...。因此,正如其他人所说,请添加异常的堆栈跟踪,以便我们有更多的工作要做。我不知道您使用的是哪个 IDE,但在 Eclipse 中我没有获得 NRE,而且您的代码对我来说似乎很好。
  • 这是堆栈跟踪...我也在使用 Eclipse,但我不确定我使用的是什么编译器...

标签: java oop user-interface nullpointerexception calling-convention


【解决方案1】:

你永远不会初始化你的成员变量HashSet&lt;Direction&gt; movement,这就是为什么你总是得到一个 NPE。

试试这个

private Set<Direction> movement = new HashSet<>();

顺便说一句,将实现类HashSet 声明为变量类型是一种不好的做法。您应该改用接口Set。

【讨论】:

  • 我添加了它,它不再给我 NPE,但我的屏幕仍然是空白的。
  • 您询问了一个空指针,这个问题已经得到解答。 “为什么屏幕是空白的”这个问题太宽泛了。尝试调试或跟踪您的应用程序并更接近根本原因。然后,如果您仍然有问题 - 问一个更有针对性的问题。除了你之外,没有人知道你试图实现什么逻辑。在这个阶段试图帮助你是困难和适得其反的。
  • 好的,无论如何,谢谢,但你能解释一下为什么将 HashSet 声明为变量是不好的吗?使用您的建议时,它似乎效果更好(但不完全)。
  • 这是一个很好的答案:stackoverflow.com/questions/147468/…
【解决方案2】:

在您的public Shoot(Ship s1) 构造函数中,您实例化new MoveAction(true, s1, Direction.LEFT), true);,使用s1,这也是字段的名称。

问题是在构造函数完成运行之前,您不能引用字段。这种情况下的行为未定义。 可能您的编译器认为您所指的s1 是该字段。我的编译器不是这样,但我不知道你用的是哪个编译器。

在任何情况下,尝试为构造函数的参数和字段赋予不同的名称 - s1,并将 参数 传递给 MoveAction(..) 构造函数。

【讨论】:

  • 这不取决于编译器。变量的范围在语言规范中定义,在此上下文中它始终是参数s1。此外,没有任何内容表明在构造函数完成之前不允许使用字段。如果该字段已正确初始化,则没有理由不使用它。所以你的答案在这两个方面都不正确。
  • 可能您对编译器范围的第一件事是正确的,正如我所说,在我的情况下这应该可以工作。但是:除此之外,这里提供的程序是正确的并且应该可以工作。第二个 - 在构造函数完成运行之前实例的状态是未定义的,因此不能对字段做出任何假设。
  • 程序可能是正确的,但你的答案不正确。正如人们在 cmets 中询问的那样,OP 需要提供更多信息,然后我们才能了解 NPE 的目标。
  • 我的回答包含两个陈述和一个一般性建议。第一个陈述(可能)是错误的,但第二个陈述和建议(不可能是错的,因为它是一个建议)很好。
  • 声明 1:编译器可能将 s1 解释为 this.s1。 不正确。声明 2:在构造函数完成运行之前,您不得引用字段。 不正确。建议:替换变量名。但这个变量与问题无关。因此不能解决 OP 的问题,因此该建议无益且令人困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 2014-05-01
  • 1970-01-01
相关资源
最近更新 更多