Java VTD-XML:在初始化对象之后,它们仍然引用null

Java VTD-XML:在初始化对象之后,它们仍然引用null,java,vtd-xml,Java,Vtd Xml,问题是:在构造函数中初始化VTDGen、VTDNav或AutoPilot之后,在另一个方法中,它们引用null并引发相应的异常 public class Configuration { public Configuration(String dir, String filename, ResourceBundle resourceBundle) throws IOException, IndexWriteException, IndexReadException { String XML

问题是:在构造函数中初始化VTDGen、VTDNav或AutoPilot之后,在另一个方法中,它们引用null并引发相应的异常

public class Configuration {
public Configuration(String dir, String filename, ResourceBundle resourceBundle) throws IOException, IndexWriteException, IndexReadException {
    String XMLFilename = filename + ".xml";
    String indexFilename = filename + ".vxl";
    vtdGen = new VTDGen();

    vtdGen.parseFile("D:/Librarian/config/configuration.xml", true);
    vtdNav = vtdGen.getNav();
    autoPilot = new AutoPilot(vtdNav);
    boolean gen = vtdGen!=null;
    boolean nav =  vtdNav!=null;
    boolean pilot = autoPilot!= null;
    System.out.println("VTDGEN - " + gen + "\n" + "VTDNAV - " + nav + "\n" + "AUTOPILOT - " + pilot + "\n");
}

public Configuration(ResourceBundle resourceBundle) {
    try {
        new Configuration(defaultDir, defaultFileName, resourceBundle);
    } catch (IOException | IndexWriteException | IndexReadException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
}

public ArrayList<String> stringValue(String xPathExpression) {
    try {
        boolean pilot = autoPilot != null;
        System.out.println("AUTOPILOT - " + pilot + "\n" + "String.length = " + xPathExpression.length() + "\n" + "String = " + xPathExpression);
        autoPilot.selectXPath(xPathExpression);
        int i;
        while ((i = autoPilot.evalXPath())!=-1) {
            stringResult.add(vtdNav.toString(i));
        }
    } catch (XPathEvalException | NavException | XPathParseException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
    return stringResult;
}

public void writeIndex(File indexFile) {
    try (FileOutputStream fos = new FileOutputStream(indexFile)){
        if (parsed) {
            vtdGen.writeIndex(fos);
        }
    } catch (IndexWriteException | IOException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
}

public File createIndexFile(String dir, String filename){
    indexFile = new File(dir + filename + ".vxl");
    writeIndex(indexFile);
    return indexFile;
}

private final String defaultDir = System.getProperty("user.dir") + "/config/";
private final String defaultFileName = "configuration";
private final String defaultXMLFile = defaultFileName + ".xml";
private final String defaultIndexFile = defaultFileName + ".vxl";

private boolean parsed;
private VTDGen vtdGen;
private VTDNav vtdNav;
private AutoPilot autoPilot;
private File indexFile;
private ArrayList<String> stringResult;
}
例外情况:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.NullPointerException
at core.config.Configuration.stringValue(Configuration.java:45)
at UI.PrimaryStageController.test(PrimaryStageController.java:77)
... 57 more

为什么自动驾驶仪引用null?

我猜您正在调用此构造函数:

public Configuration(ResourceBundle resourceBundle) {
    try {
        new Configuration(defaultDir, defaultFileName, resourceBundle);
    } catch (IOException | IndexWriteException | IndexReadException e) {
        e.printStackTrace(); 
    }
}
public Configuration(ResourceBundle resourceBundle) {
    try {
        new Configuration(defaultDir, defaultFileName, resourceBundle);
    } catch (IOException | IndexWriteException | IndexReadException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
}
那不是你想象的那样。它试图创建一个新的
配置
对象,但实际上并不使用它。无论该构造函数是否成功完成,该实例中的所有实例变量都将具有其默认值

您可以使用
this
链接到另一个构造函数,但是您必须声明此构造函数可以抛出相同的已检查异常:

public Configuration(ResourceBundle resourceBundle)
    throws IOException, IndexWriteException, IndexReadException {
    this(defaultDir, defaultFileName, resourceBundle);
}
当链接到另一个构造函数时,无法捕获异常

如果您真的(真的,真的)想要抑制这样的异常,您可能应该将其转换为静态方法,并确保返回对新构造的实际数据对象的引用

public static Configuration fromResourceBundle(ResourceBundle resourceBundle) {
    try {
        return new Configuration(defaultDir, defaultFileName, resourceBundle);
    } catch (IOException | IndexWriteException | IndexReadException e) {
        // Swallowing exceptions? Really?
        e.printStackTrace();
        // At least the caller will get a null reference back instead of
        // a broken object...
        return null;
    }
}
使用此:

public Configuration(ResourceBundle resourceBundle) throws Exception {
    this(Configuration(defaultDir, defaultFileName, resourceBundle));
}
在构造函数中:

public Configuration(ResourceBundle resourceBundle) {
    try {
        new Configuration(defaultDir, defaultFileName, resourceBundle);
    } catch (IOException | IndexWriteException | IndexReadException e) {
        e.printStackTrace(); 
    }
}
public Configuration(ResourceBundle resourceBundle) {
    try {
        new Configuration(defaultDir, defaultFileName, resourceBundle);
    } catch (IOException | IndexWriteException | IndexReadException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
}
您创建了另一个提供输出的配置实例

VTDGEN - true
VTDNAV - true
AUTOPILOT - true
您正在调用另一个实例上的方法,该实例使用字段的默认值初始化

编辑


正如Jon Skeet所指出的,您需要抛出异常。在构造函数中接受异常是一种糟糕的做法,因为您成功地从构造函数返回,并且对象没有正确初始化

谢谢您,Jon!我在这上面加了一条注释