提问者:小点点

Java空指针超时调用getter在另一个类,即使getter的返回值不为空


我在17java使用JavaFX(使用fxml)和java套接字编写消息传递应用程序。我设法与服务器建立了通信,在我的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

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


共1个答案

匿名用户

注释为@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();

    }

}