在另一个类中调用 getter 时出现 Java 空指针异常,即使 getter 的返回值不为空

问题描述 投票:0回答:1

我正在使用 JavaFX(带有 fxml)和 Java 套接字在 Java 17 中编写消息传递应用程序。我设法与服务器建立了通信,在我的 Client.java 中,我想发送 gui 文本区域(写入消息)中的任何内容。此 gui 由 AppController 类控制。当我调用 appController.getMessageArea().getText() 我得到一个空指针异常(下面的错误日志)

这里是我的 CLient.java

public class Client {

    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private String username;
    private AppController appController;

    public Client(Socket socket, String username) throws IOException {
        this.appController = new AppController();
        try {
            this.socket = socket;
            this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.out = new PrintWriter(socket.getOutputStream(), true);
            this.username = username;
            out.println(username);
        } catch (IOException e) {
            closeAll();
        }
    }

    public void send() {
        String message;
        try {
            while(socket.isConnected()){
                message = appController.getMessageArea().getText();
                out.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //closeAll(socket, in, out);
        }
    }

    public void closeAll(Closeable... objects){
        for(Closeable c : objects){
            try {
                c.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void listen(){
        new Thread(() -> {
            String receivedMessage;
            while(socket.isConnected()){
                try{
                    receivedMessage = in.readLine();
                    Label received = new Label(receivedMessage);
                    appController.getMessageContainer().getChildren().add(received);
                    appController.getScrollPane().setVvalue(1.0);

                }catch(Exception e){
                    closeAll(socket, in, out);
                }

            }
        }).start();
    }

    public Socket getSocket() {
        return socket;
    }

    public String getUsername() {
        return username;
    }
}

这里是 AppController.java

public class AppController implements Initializable {

    @FXML
    private TextArea messageArea;
    @FXML
    private VBox messageContainer;
    @FXML
    private ScrollPane scrollPane;
    @FXML
    private Label nameTag;
    @FXML
    private Button sendButton;

    private Client client;


    @Override
    public void initialize(URL url, ResourceBundle resources){
        try{
            System.out.println(getMessageArea());
            messageArea.clear();
            sendButton.disableProperty().bind(messageArea.textProperty().isEmpty());
            nameTag.setText(LoginController.user.getName());
            client = new Client(new Socket("localhost", 1234), LoginController.user.getName());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void send(){
       //String message = messageArea.getText();
       Label sent = new Label(client.getUsername() + "> " + messageArea.getText());
       messageContainer.getChildren().add(sent);
       scrollPane. setVvalue(1.0);
       client.send();
       messageArea.clear();

    }

    public VBox getMessageContainer() {
        return messageContainer;
    }

    public ScrollPane getScrollPane() {
        return scrollPane;
    }

    public TextArea getMessageArea() {
        return messageArea;
    }
}

这是错误日志

java.lang.NullPointerException: Cannot invoke "javafx.scene.control.TextArea.getText()" because the return value of "messageapp.AppController.getMessageArea()" is null
    at messageapp/messageapp.util.Client.send(Client.java:35)
    at messageapp/messageapp.AppController.send(AppController.java:47)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:77)
    at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:84)
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1854)
    at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1724)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8792)
    at javafx.controls/javafx.scene.control.Button.fire(Button.java:203)
    at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:208)
    at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3897)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1878)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2623)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449)
    at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:557)
    at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:943)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
    at java.base/java.lang.Thread.run(Thread.java:833)

Process finished with exit code 0

如果你还需要什么告诉我!谢谢

java sockets javafx nullpointerexception
1个回答
0
投票

带注释的字段

@FXML
在控制器中初始化,控制器(通常)是创建的对象。
FXMLLoader
每次加载相应的 FXML 文件时。它们不会神奇地在同一类的任意对象中被初始化(即使是,它们会被初始化成什么?)。

如果你想在你的

Client
类中引用控制器,你需要给它一个由
FXMLLoader
创建的实际控制器实例的引用。

反正这里的设计很丑。您的

Client
类不知道控制器有一个
TextArea
并且永远不应该访问它。这明显违反了关注点分离,并且很难在不更改应用程序代码的任意其他部分的情况下更改 UI 设计(使用不同的控件)。

相反,定义您的

Client.send()
方法以获取表示要发送的消息的参数,然后从控制器相应地调用它。这避免了空指针异常并修复了丑陋的设计。

public class Client {

    // ...

    public void send(String message) {

        // this implementation looks wrong. Why are you repeatedly sending the message?

        try {
            while(socket.isConnected()){
                out.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //closeAll(socket, in, out);
        }
    }

}

然后

public class AppController implements Initializable {

    @FXML
    private TextArea messageArea;
    @FXML
    private VBox messageContainer;

    // ...

    public void send(){
       String message = messageArea.getText();
       Label sent = new Label(client.getUsername() + "> " + message);
       messageContainer.getChildren().add(sent);
       scrollPane. setVvalue(1.0);
       client.send(message);
       messageArea.clear();

    }

}
© www.soinside.com 2019 - 2024. All rights reserved.