疑问:通过JFrame设置System.in后Scanner无法读取输入,是操作有误还是不可行?
问题原因与解决方案
核心问题
你遇到的问题根源在于:Scanner实例在创建时就绑定了当前的System.in输入流。你的Main线程是在启动GUI后立刻创建了Scanner并开始读取,此时Scanner关联的是默认的控制台输入流;后续点击按钮通过System.setIn()替换System.in的指向,已经存在的Scanner并不会自动切换到新的输入流,所以始终读不到你设置的内容。
而System.out的打印操作正常,是因为每次调用System.out.println()等方法时,都会直接使用当前System.out的指向,所以替换后能立刻生效——这和Scanner的绑定逻辑完全不同。
解决方案
方案一:延迟创建Scanner,待输入流替换完成后再初始化
让主线程等待GUI按钮触发输入流替换的信号,之后再创建Scanner读取新的输入流:
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.ByteArrayInputStream; import java.util.Scanner; public class WriteToSystemIn extends JFrame { private static final Object LOCK = new Object(); public WriteToSystemIn() { JButton button = new JButton("设置输入"); button.addActionListener(e -> { ByteArrayInputStream bais = new ByteArrayInputStream("1\n".getBytes()); System.setIn(bais); // 通知主线程可以读取 synchronized (LOCK) { LOCK.notify(); } dispose(); }); add(button); setSize(300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(WriteToSystemIn::new); // 主线程等待输入流替换完成 synchronized (LOCK) { try { LOCK.wait(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); return; } } // 此时System.in已被替换,创建Scanner读取 Scanner scanner = new Scanner(System.in); if (scanner.hasNextLine()) { System.out.println("读取到的内容:" + scanner.nextLine()); } scanner.close(); } }
方案二:直接使用自定义输入流创建Scanner(更推荐)
如果不需要全局替换System.in,只是想让Scanner读取指定内容,完全可以跳过修改System.in的步骤,直接给Scanner传入自定义的输入流,这种方式更灵活,也避免了全局替换可能带来的其他问题:
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.ByteArrayInputStream; import java.util.Scanner; public class WriteToSystemIn extends JFrame { public WriteToSystemIn() { JButton button = new JButton("读取自定义输入"); button.addActionListener(e -> { ByteArrayInputStream bais = new ByteArrayInputStream("1\n".getBytes()); Scanner scanner = new Scanner(bais); if (scanner.hasNextLine()) { System.out.println("读取到的内容:" + scanner.nextLine()); } scanner.close(); }); add(button); setSize(300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(WriteToSystemIn::new); } }
内容的提问来源于stack exchange,提问作者Jun
相关产品推荐
相关产品推荐

