提问人:Anthrax 提问时间:5/18/2023 更新时间:5/18/2023 访问量:81
在另一个类中调用 getter 时,Java null 指针超出,即使 getter 的返回值不是 null [duplicate]
Java null pointer excepetion when invoking getter in another class, even though getter's return value is not null [duplicate]
问:
我正在使用 JavaFX(带有 fxml)和 java 套接字在 java 17 中编写一个消息传递应用程序。我设法与服务器建立了通信,并且在我的客户端.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
如果你需要什么,告诉我!谢谢
答:
3赞
James_D
5/18/2023
#1
带注释的字段在控制器中初始化,控制器(通常)是创建对象。每次加载相应的 FXML 文件时。它们不会神奇地在同一类的任意对象中被初始化(即使它们被初始化,它们也会被初始化为什么?@FXML
FXMLLoader
如果要在类中引用控制器,则需要向它提供对 创建的实际控制器实例的引用。Client
FXMLLoader
无论如何,这里的设计很丑陋。你的类不知道控制器有一个并且不应该访问它。这显然违反了关注点分离,并且很难在不更改应用程序代码的任意其他部分的情况下更改 UI 设计(以使用不同的控件)。Client
TextArea
相反,请定义方法以采用表示要发送的消息的参数,然后从控制器相应地调用它。这避免了空指针异常,并修复了丑陋的设计。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();
}
}
评论
0赞
Anthrax
5/19/2023
是的,这是我首先做的(将要发送的消息作为客户端中发送方法的参数),但这似乎也不起作用。我会再试一次,我肯定做错了什么。我还将按照您的建议尝试 MVC 架构,这应该可以解决其他问题并使代码更具可读性。感谢您抽出宝贵时间接受采访
1赞
James_D
5/19/2023
@Anthrax 显然,你的代码中还有很多其他错误。我刚刚解决了你明确提出的问题。首先要发生的情况是,您的方法进入了一个本质上无限循环,并且似乎在 FX 应用程序线程上被调用,因此应用程序将挂起并一遍又一遍地重复发送消息(正如我在代码的注释中暗示的那样)。send()
评论
@FXML
-带注释的字段(例如 )将仅在控制器中初始化。它们不会仅仅因为它们碰巧属于同一类而在任意对象中初始化。您的类需要对实际控制器的引用(加载和显示 FXML 文件时由 创建的控制器)。(或者,可能更好的是,使用 MVC 方法并从模型中获取数据,这样您就不会在表示层之外公开 UI 元素。messageArea
Client
FXMLLoader
@FXML
FXMLLoader
System.out.println("From getMessageArea, returning: "+messageArea);
getMessageArea()
return
null
listen()