简体   繁体   中英

JavaFx invocation target exception when I try to initialize class

Im really new to javafx and i guess im missing some of the logic here. My class BankApplication contains instance variables Customer and SavingsAccount. I want to initialize those so my application will run, with the name of customer and the ID on the top, as well as the balance. So I want to create an instance of BankApplication , to give the app this information. It gives me an error.

This is just a part of the code..

public class BankApplication extends Application implements 
EventHandler<ActionEvent>{

public static void main(String[] args) {

    Customer Amanda = new Customer("Amanda" , 1009);
    SavingsAccount AmandaBANK = new SavingsAccount(Amanda , 150);
    BankApplication app1 = new BankApplication(Amanda,AmandaBANK);

    launch(args);

}

protected Customer customer;
protected SavingsAccount bankAccount;

public BankApplication(Customer customer, SavingsAccount bankAccount) {
    this.customer = customer;
    this.bankAccount = bankAccount;
}

private Button executeButton = new Button("Execute");
Label customerNameLabel = new Label("Customer name: " + customer.getName());
Label customerIDLabel = new Label("Customer ID: "+ customer.getID());

Label balanceLabel = new Label("Current balance: $" + 
bankAccount.getBalance() + ".");
TextField depositTextField = new TextField("Amt to deposit");
TextField withdrawTextField = new TextField("Amt to withdraw");



@Override
public void start(Stage primaryStage) throws Exception {

    FlowPane root = new FlowPane();
    Scene scene = new Scene(root,400,300);
    primaryStage.setScene(scene);
    primaryStage.setTitle("Bank application");

    executeButton.setOnAction(this);

    HBox middle = new HBox(depositTextField,withdrawTextField);
    middle.setSpacing(8);
    middle.setPadding(new Insets(8));

    VBox top = new VBox(customerNameLabel,customerIDLabel);
    VBox bottom = new VBox(executeButton,balanceLabel);
    top.setSpacing(8);
    bottom.setSpacing(8);
    top.setPadding(new Insets(8));
    bottom.setPadding(new Insets(8));

    root.getChildren().add(top);
    root.getChildren().add(middle);
    root.getChildren().add(bottom);


    primaryStage.show();


}

@Override
public void handle(ActionEvent event) {
    if (event.getSource() == executeButton) {

        String depositAmount = depositTextField.getText();
        String withdrawAmount = withdrawTextField.getText();

        if (isDouble(depositAmount) == true) {

            double old_balance = bankAccount.getBalance();

            bankAccount.deposit(Double.parseDouble(depositAmount));

            double new_balance = bankAccount.getBalance();

            if (new_balance != old_balance) { 
                updateBalanceLabel();
                depositTextField.clear();
                depositTextField.setText("Amt to deposit"); 
            }

            else if (new_balance == old_balance) { 
                depositTextField.clear();
                depositTextField.setText("Amt to deposit"); 
            }
        }

And the javafx error..

java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)


Caused by: java.lang.NullPointerException
at BankAccount.BankApplication.<init>(BankApplication.java:37)
at BankAccount.BankApplication.main(BankApplication.java:22)
... 11 more
Exception running application BankAccount.BankApplication

You initialize several instance variables (customerIDLabel, customerIDLabel) based on customer and account that are passed to constructor. The problem is, java calls your constructor after the field initialization block. This is easy to fix: just move field initialization code into your constructor:

protected Customer customer;
protected SavingsAccount bankAccount;
private Button executeButton = new Button("Execute");
private Label customerIDLabel;
private Label balanceLabel;
private TextField depositTextField;
private TextField withdrawTextField;
private Label customerNameLabel;

public BankApplication(Customer customer, SavingsAccount bankAccount) {
    this.customer = customer;
    this.bankAccount = bankAccount;
    customerNameLabel = new Label("Customer name: " + customer.getName());
    customerIDLabel = new Label("Customer ID: " + customer.getID());

    balanceLabel = new Label("Current balance: $" +
            bankAccount.getBalance() + ".");
    depositTextField = new TextField("Amt to deposit");
    withdrawTextField = new TextField("Amt to withdraw");
}

This would fix your NullPointerException, but did you notice that app1 is ignored? In JavaFX, you are not supposed to create instances of your Application. Instead, you have to let JavaFx runtime to do it for you. Here it is generally considered acceptable to use statics.

public class BankApplication extends Application implements
    EventHandler<ActionEvent> {
private static Customer customer;
private static SavingsAccount bankAccount;

private Button executeButton = new Button("Execute");
private Label customerIDLabel;
private Label balanceLabel;
private TextField depositTextField;
private TextField withdrawTextField;
private Label customerNameLabel;

public static void main(String[] args) {
    customer = new Customer("Amanda", 1009);
    bankAccount = new SavingsAccount("Amanda", 150);

    Application.launch(args);

}

public BankApplication() {
    customerNameLabel = new Label("Customer name: " + customer.getName());
    customerIDLabel = new Label("Customer ID: " + customer.getID());

    balanceLabel = new Label("Current balance: $" +
            bankAccount.getBalance() + ".");
    depositTextField = new TextField("Amt to deposit");
    withdrawTextField = new TextField("Amt to withdraw");
}


@Override
public void start(Stage primaryStage) throws Exception {

    FlowPane root = new FlowPane();
    Scene scene = new Scene(root, 400, 300);
    primaryStage.setScene(scene);
    primaryStage.setTitle("Bank application");

    executeButton.setOnAction(this);

    HBox middle = new HBox(depositTextField, withdrawTextField);
    middle.setSpacing(8);
    middle.setPadding(new Insets(8));

    VBox top = new VBox(customerNameLabel, customerIDLabel);
    VBox bottom = new VBox(executeButton, balanceLabel);
    top.setSpacing(8);
    bottom.setSpacing(8);
    top.setPadding(new Insets(8));
    bottom.setPadding(new Insets(8));

    root.getChildren().add(top);
    root.getChildren().add(middle);
    root.getChildren().add(bottom);


    primaryStage.show();


}

@Override
public void handle(ActionEvent event) {
    if (event.getSource() == executeButton) {

        String depositAmount = depositTextField.getText();
        String withdrawAmount = withdrawTextField.getText();

        if (isDouble(depositAmount) == true) {

            double old_balance = bankAccount.getBalance();

            bankAccount.deposit(Double.parseDouble(depositAmount));

            double new_balance = bankAccount.getBalance();

            if (new_balance != old_balance) {
                updateBalanceLabel();
                depositTextField.clear();
                depositTextField.setText("Amt to deposit");
            } else if (new_balance == old_balance) {
                depositTextField.clear();
                depositTextField.setText("Amt to deposit");
            }
        }
    }
}//...

When a JavaFX application is launched (either by a call to Application.launch() , or by the system directly), a number of things happen "automatically".

One of these is that an instance of your Application subclass is created via a call to the no-argument constructor.

Another thing that happens is that the start() method is invoked on the instance that is created. (This happens on the FX Application Thread).

The consequence of this is that:

  1. You must have a no-argument constructor in your Application subclass
  2. You should consider the start() method as the entry point of the application; ie the first thing that happens. Any initialization should be done here. you should (in general) avoid having anything in the main() method except a call to launch() .

So you can restructure your application class as:

public class BankApplication extends Application implements EventHandler<ActionEvent>{

    public static void main(String[] args) {

        launch(args);

    }

    protected Customer customer;
    protected SavingsAccount bankAccount;


    private Button executeButton ;
    private Label customerNameLabel ;
    private Label customerIDLabel ;

    private Label balanceLabel ;
    private TextField depositTextField ;
    private TextField withdrawTextField ;



    @Override
    public void start(Stage primaryStage) throws Exception {

        Customer customer = new Customer("Amanda" , 1009);
        SavingsAccount bankAccount = new SavingsAccount(Amanda , 150);

        executeButton = new Button("Execute");
        customerNameLabel = new Label("Customer name: " + customer.getName());
        customerIDLabel = new Label("Customer ID: "+ customer.getID());

        balanceLabel = new Label("Current balance: $" + 
                              bankAccount.getBalance() + ".");
        depositTextField = new TextField("Amt to deposit");
        withdrawTextField = new TextField("Amt to withdraw");


        FlowPane root = new FlowPane();
        Scene scene = new Scene(root,400,300);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Bank application");

        executeButton.setOnAction(this);

        HBox middle = new HBox(depositTextField,withdrawTextField);
        middle.setSpacing(8);
        middle.setPadding(new Insets(8));

        VBox top = new VBox(customerNameLabel,customerIDLabel);
        VBox bottom = new VBox(executeButton,balanceLabel);
        top.setSpacing(8);
        bottom.setSpacing(8);
        top.setPadding(new Insets(8));
        bottom.setPadding(new Insets(8));

        root.getChildren().add(top);
        root.getChildren().add(middle);
        root.getChildren().add(bottom);


        primaryStage.show();


    }

    @Override
    public void handle(ActionEvent event) {
        // ...
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM