(Java)代码在使用子类时有效,但使用超类会导致空指针错误?

时间:2015-10-23 23:59:53

标签: java nullpointerexception

我正在编写一个程序来玩黑桃。

我有一个班级,GenericSpadesPlayer

和两个子类

SpadesPlayer扩展了GenericSpadesPlayer(这些是计算机播放器。),和 HumanSpadesPlayer扩展了GenericSpadesPlayer

GenericSpadesPlayerClass的全部内容如下:

import java.io.*;
import java.util.*;

    public abstract class GenericSpadesPlayer{

      Set<Card> hand;
      int playerKey;

  public abstract Card playCard(Card[] playedCards, int[] bids, int[] tricksTaken, int leadSuit);
  public abstract int getBid();

}

这些成员变量和方法中的每一个都在SpadesPlayer和HumanSpadesPlayer类中实现,并且这两个类的编译都没有错误。

问题在于运行游戏的类的主要方法。最初,我只创建了SpadesPlayer对象,我的代码是:

SpadesPlayer north = new SpadesPlayer(3);
SpadesPlayer south = new SpadesPlayer(1);
SpadesPlayer east = new SpadesPlayer(4);
SpadesPlayer west = new SpadesPlayer(2);

SpadesPlayer[] rotation = {south, west, north, east};

然后,当我发卡时:

for (int i=0; i<deck.deck.length; i++){
  rotation[currentPos].hand.add(deck.dealCard()); //currentPos is initialized to be 1
  currentPos = (currentPos + 1) % 4;
}

一切正常。

当我开发GenericSpadesPlayer类并允许SpadesPlayer和HumanSpadesPlayer继承它时,问题出现了。当我改变时:

SpadesPlayer[] rotation = {south, west, north, east};

GenericSpadesPlayer[] rotation = {south, west, north, east};

,我在以下一行收到错误:

rotation[currentPos].hand.add(deck.dealCard());

尝试调试后,程序说旋转[currentPos] .hand为空。 GenericSpadesPlayer中没有初始化Hand,因为它是一个抽象类;但是,南,西,北和东(旋转数组的所有元素)都是SpadesPlayers或HumanSpadesPlayers,并且hand在其构造函数中初始化。还应该注意的是,无论我在旋转数组中包含什么样的SpadesPlayers或HumanSpadesPlayers,我总是会遇到这个错误,只要将旋转声明为GenericSpadesPlayers而不是SpadesPlayers的数组。

有什么建议吗?我想制作一系列GenericSpadesPlayers可以让我用SpadesPlayers和HumanSpadesPlayers填充它,但我似乎遇到了问题。

1 个答案:

答案 0 :(得分:1)

  

这些成员变量和方法中的每一个都在SpadesPlayer和HumanSpadesPlayer类中实现,并且这两个类的编译都没有错误。

我怀疑这是问题所在。如果您在子类中重新声明Set<Card> hand,它将覆盖超类中的Set<Card> hand。然后,一旦将数组从子类切换到超类,您将获得零点异常。

您不需要在子类中重新声明Set<Card> hand,您可以自由访问它们。从类继承时,您可以访问其所有变量和方法。你只能在你的子类代码中看到它们。

这是一个简单的例子。

超级List,未初始化。如果我尝试使用这个变量,我将得到一个空指针异常。

public class mySuper {

    public static List<Integer> test;

}

继承自上述类的子类。我重新声明了变量,这是我认为你做的。我也初始化它,所以如果我尝试使用这个变量,我将不会得到空指针异常。

public class mySub extends mySuper{

    public static List<Integer> test = new ArrayList<Integer>();

}

主要方法,类似于你的。

public static void main(String[] args){
        mySub[] mySubArray = {new mySub()};
        System.out.println(mySubArray[0].test.size()); //prints 0

        mySuper[] mySuperArray = {new mySub()}; 
        System.out.println(mySuperArray[0].test.size()); //null pointer exception
    }

如何解决此问题。

正确初始化超类中的变量。

public class mySuper {

    public static List<Integer> test  = new ArrayList<Integer>();

}

取出子类中的声明,你仍然可以使用它。

public class mySub extends mySuper{


}

public static void main(String[] args){
        mySub[] mySubArray = {new mySub()};
        System.out.println(mySubArray[0].test.size()); //prints 0

        mySuper[] mySuperArray = {new mySub()}; 
        System.out.println(mySuperArray [0].test.size()); //prints 0
    }

您可以重新分配子类中的变量。但是,如果重新声明,那么当它覆盖超类变量时就是这样。