【问题标题】:Scanner object has a class attribute instead of in code initialisationScanner 对象具有类属性而不是代码初始化
【发布时间】:2020-05-29 05:58:36
【问题描述】:

今天,我在编写服务器/客户端应用程序时遇到了Scanner 对象的问题。我已经解决了问题,但我不明白为什么我的解决方案解决了问题。

起初,在我的应用程序中,我在编译项目时遇到了一些内存泄漏警告(JAVA 8,eclipse) 因为我使用Scanner 向用户询问输入但没有关闭它。当我尝试关闭扫描仪时,我的其他类会抛出 java.util.NoSuchElementException 之类的异常。我了解到我有类似的问题:Cannot use multiple Scanner objects in Java 但在课程之间。当我在一个类中关闭一个扫描器时,另一个类(线程)扫描器无法执行。 (java.util.NoSuchElementException)

我发现解决这个问题的解决方案是将 Scanner 函数作为类函数成员:

public class ClientThread extends Thread {

    private Scanner scanner;

   /*some code*/

}

这样做时,我失去了内存泄漏警告。

为什么让扫描仪作为班级成员解决了警告?是因为类析构函数吗?

【问题讨论】:

  • 你原来的范围是什么?不清楚
  • 我认为我的问题与变量的范围无关。我会试着换个说法。我不明白如何将扫描仪作为函数中的局部变量会导致内存泄漏而不关闭但扫描仪没有类成员变量。

标签: java multithreading oop java.util.scanner


【解决方案1】:

通常,当您创建Scanner 时,您需要在不再需要它时close

Scanner 类有几个重载的构造函数,每个构造函数都采用不同类型的参数。有一个构造函数接受 File 参数。有一个构造函数接受 Path 参数。还有一个构造函数接受InputStream 参数。为了让您的 Java 程序通过计算机键盘接受来自用户的输入,您可以使用带有 InputStream 的构造函数,如下所示:

Scanner scanner = new Scanner(System.in);

这是因为类 java.lang.System 的静态成员 in 的类型为 InputStream。您应该将System.in 视为将键盘封装在您的计算机上。如果你关闭System.in,就像关闭你的键盘一样,这是你不应该做的事情。

现在Eclipse IDE 还不够聪明,无法意识到您的代码正在创建一个基本上封装了计算机键盘的Scanner(因此不应关闭)。 Eclipse 只知道您创建的任何 Scanner 最终都应该关闭,并且由于您的代码不会关闭您创建的 ScannerEclipse 会显示一个警告,表明您没有不要关闭您创建的Scanner。在显示的警告中,您将获得三个关于如何消除警告的建议。前两个是指可以添加的注解,即

@SuppressWarnings("resource")

第三个建议要求您更改 Eclipse 配置。您可以通过选择 Eclipse IDE 顶部显示的 Window 菜单的 Preferences 项来执行此操作。在 Preferenes 窗口中,选择 Java > Compiler > Errors/Warnings 并将 Resource leak 设置更改为 Ignore,如以下屏幕截图所示:

但请注意,此配置设置适用于 所有 资源,而不仅仅是 Scanner,因此如果您在 java 代码中打开一个常规文件并且不关闭它,Eclipse 不会警告你。

就我个人而言,我只是忽略了警告,因为我知道我不应该关闭使用 System.in 创建的 Scanner 或添加注释。

【讨论】:

  • 为什么不直接安排您的代码,以便创建一个 System.in 扫描程序,并在应用程序结束时关闭它?
  • 是的,这是一个选项,但我想知道为什么将 Scanner 放在一个类成员中删除指示 Scanner 未关闭的警告。在我的第一个程序版本中,Scanner 是一个局部变量,要求在函数中获取一些信息就像 Abra 解释的那样,我使用 System.in 有其他 Scanner 变量。但是当我将 Scanner 作为类成员时,不再有内存泄漏警告。如何放置一个扫描器变量有一个类成员避免内存泄漏
【解决方案2】:

虽然 Java 通常会在您离开作用域时自动释放内存,但某些类需要特殊处理。

通常这些类与文件和连接(到数据库或只是套接字)有关。 后者是必需的,因为底层操作系统需要显式释放这些资源(通常)。

在 Java 8 中引入了Autoclosable,它解决了一些问题,但最终你需要小心。

这是一个带有自动关闭功能的扫描仪示例:

File file = new File("filename here");
try (Scanner in = new Scanner(file)) {
    // do something here, note you dont need close as it is autoclosable
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-31
    • 2015-11-29
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-01
    • 2016-10-26
    相关资源
    最近更新 更多