java JMenuItem Nullpointerexception(重写swing类时初始化时出错)

java JMenuItem Nullpointerexception(重写swing类时初始化时出错),java,swing,nullpointerexception,initialization,jmenuitem,Java,Swing,Nullpointerexception,Initialization,Jmenuitem,我正在做一个项目,并取得了良好的进展,直到我偶然发现一个意想不到的例外。它是由一个JMenuItem的初始化引起的,有些令人惊讶,就像我以前做过类似的事情一样。我发现类(class2)工作正常,如果它不是JMenuItem(class4)的子类。我还找到了一个解决方法(class3),但我仍然想知道,我做错了什么。我搜索了一个答案,但没有找到答案,可能是因为搜索条件不好。有人有什么想法吗 import javax.swing.JMenuItem; class class1 { publ

我正在做一个项目,并取得了良好的进展,直到我偶然发现一个意想不到的例外。它是由一个JMenuItem的初始化引起的,有些令人惊讶,就像我以前做过类似的事情一样。我发现类(class2)工作正常,如果它不是JMenuItem(class4)的子类。我还找到了一个解决方法(class3),但我仍然想知道,我做错了什么。我搜索了一个答案,但没有找到答案,可能是因为搜索条件不好。有人有什么想法吗

import javax.swing.JMenuItem;

class class1 {
    public static void main(String[] f) {
        System.err.println(new class3(0));
        System.err.println(new class3(1));
        System.err.println(new class4(0));
        new class2(1);
    }
}

class class2 extends JMenuItem {
    static String[] a;
    int b;

    {
        a = new String[2];
        a[0] = "c";
        a[1] = "d";
    }

    public class2(int e) {
        super();
        b = e;
    }

    public String getText() {
        return a[b];
    }

    public String toString() {
        return class2.class + ": " + b + ", " + getText();
    }
}

class class3 extends JMenuItem {
    static String[] a;
    int b;

    {
        a = new String[2];
        a[0] = "c";
        a[1] = "d";
    }

    public class3(int e) {
        super();
        b = e;
    }

    public String getText() {
        if ( b == 0 ) return "g";
        return a[b];
    }

    public String toString() {
        return class3.class + ": " + b + ", " + getText();
    }
}

class class4 {
    static String[] a;
    int b;

    {
        a = new String[2];
        a[0] = "c";
        a[1] = "d";
    }

    public class4(int e) {
        super();
        b = e;
    }

    public String getText() {
        return a[b];
    }

    public String toString() {
        return class4.class + ": " + b + ", " + getText();
    }
}
当我执行这个类时,就会发生这种情况:

$ javac class1.java 
$ java -showversion class1
java version "1.8.0_73"
Java(TM) SE Runtime Environment (build 1.8.0_73-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode)

class class3: 0, g
class class3: 1, d
class class4: 0, c
Exception in thread "main" java.lang.NullPointerException
    at class2.getText(class1.java:29)
    at javax.swing.AbstractButton.setModel(AbstractButton.java:1779)
    at javax.swing.JMenuItem.setModel(JMenuItem.java:173)
    at javax.swing.JMenuItem.<init>(JMenuItem.java:150)
    at javax.swing.JMenuItem.<init>(JMenuItem.java:110)
    at class2.<init>(class1.java:24)
    at class1.main(class1.java:8)
$javac class1.java
$java-showversion class1
java版本“1.8.0_73”
Java(TM)SE运行时环境(build 1.8.0_73-b02)
Java HotSpot(TM)64位服务器虚拟机(构建25.73-b02,混合模式)
类别3:0,g
班级3:1,d
类别4:0,c
线程“main”java.lang.NullPointerException中出现异常
在class2.getText(class1.java:29)
位于javax.swing.AbstractButton.setModel(AbstractButton.java:1779)
位于javax.swing.JMenuItem.setModel(JMenuItem.java:173)
位于javax.swing.JMenuItem。(JMenuItem.java:150)
位于javax.swing.JMenuItem。(JMenuItem.java:110)
在class2。(class1.java:24)
在class1.main(class1.java:8)

最后,一个NullPointerException问题不是您的问题

如果您查看或为方法提供了一个
@Override
注释,您将看到
public String getText()
是一个超级方法的重写,特别是一个JMenuItem的父级AbstractButton的方法,并且似乎超级的构造函数正在调用它,在调用实例初始值设定项块之前调用它,这将导致NPE

此问题说明了以下情况下可能发生的风险:

  • 您可以扩展复杂的类
  • 类在其构造函数中调用非最终实例方法(Swing作者这样做真让人羞愧)
  • 静态字段不是以静态方式初始化的
为您提供的解决方案包括:

  • 倾向于使用组合而不是继承,尤其是在处理大型复杂类时
  • 对静态字段使用静态初始值设定项块
  • 除非有明确的需要,否则避免使用静态字段
  • 在创建方法时检查您是否在无意中重写实例方法。特别是当我无意中为一个扩展了JPanel的类重写了
    public int getX()
    public int getY()
    ,然后想知道为什么我的布局管理器不能正常工作时,我被这一点烧坏了

顺便提一下,这个问题问得很好,您发布了一个极其简化的程序,没有任何漏洞,这充分说明了您的问题。这是刷新看到一个新手到这个网站。