【问题标题】:Why don't I have to import classes not used as variable types in Java?为什么我不必导入在 Java 中不用作变量类型的类?
【发布时间】:2013-07-07 07:26:45
【问题描述】:

这是一个例子:

import java.util.HashMap;

public class Test
{
    public static void main(String[] args)
    {
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("leorum", 1);
        map.put("ipsum", 2);
        map.put("dolor", 3);

        System.out.println(map.keySet().toString());
    }
}

一切都编译并运行良好。但是,当我将 map.keySet() 移动到另一个变量时:

import java.util.HashMap;

public class Test
{
    public static void main(String[] args)
    {
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("leorum", 1);
        map.put("ipsum", 2);
        map.put("dolor", 3);

        Set<String> keys = map.keySet();
        System.out.println(keys.toString());
    }
}

我收到一个错误:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
    Set cannot be resolved to a type
    at Test.main(Test.java:12)

我明白为什么我在第二个示例中收到错误,但为什么我在第一个示例中没有收到错误? java编译器怎么知道map.keySet()在不导入java.util.Set的情况下返回什么?

我在其他编程语言中也看到过这种行为,尤其是 C++。

【问题讨论】:

    标签: java class import


    【解决方案1】:

    import 指令是一个纯粹的语法特性,它允许您引用一个类型而不用包名限定它。

    由于您的第一个代码从不引用 Set 类型,因此无需导入即可正常工作。

    import使用类无关;它只会影响你如何写它的名字。

    【讨论】:

      【解决方案2】:

      我明白为什么我在第二个示例中收到错误,但为什么我在第一个示例中没有收到错误? java编译器怎么知道map.keySet()在不导入java.util.Set的情况下返回什么?

      无论哪种方式,它都知道——它是字节码中元数据的一部分。

      它不知道你所说的Set&lt;String&gt; 是什么意思。导入只会更改源代码中名称的含义 - 并且该名称不会出现在第一段代码中的源代码中。

      来自section 7.5 of the JLS

      导入声明允许通过由单个标识符组成的简单名称(第 6.2 节)来引用命名类型或静态成员。

      您没有在第一个示例中引用简单名称,因此上述好处无关紧要。

      换句话说,导入只允许这一行(这在您的第二个示例中有效):

      java.util.Set<String> keys = map.keySet();
      

      写成:

      Set<String> keys = map.keySet();
      

      就是这样。

      【讨论】:

        【解决方案3】:

        因为在第一个示例中 keySet() 是在 HashMap 对象中执行的,而不是在您的 main 中,这就是您不需要声明它的原因。

        【讨论】:

          【解决方案4】:

          在第一种情况下,map.keySet() 的类型是已知的。返回类型是方法契约的一部分。

          在第二种情况下,不合格的名称Set不足以识别变量keys的类型。完全限定的类型名称不是从赋值的右侧推断出来的。您可以完全限定名称,也可以导入它。

          【讨论】:

            【解决方案5】:

            java 编译器知道map.keySet() 返回什么,因为它在HashMap 的定义中。

            public Set<K> keySet() { ... }
            

            编译 HashMap 时,编译器知道 Set&lt;&gt; 是什么,因为在 HashMap 的源代码中有一个 import 语句(或者更确切地说,在这种情况下,不需要 import 语句,因为 Set 在同一个HashMap)。

            然后编译器将这些信息放到编译好的类文件中,作为方法“签名”的返回类型。

            当您使用map.keySet() 时,您不必指定方法的返回类型,因为编译器可以访问 HashMap 的类文件,因此它知道所需的一切。

            【讨论】:

              猜你喜欢
              • 2019-08-27
              • 2021-11-08
              • 2018-11-26
              • 2014-07-05
              • 2011-09-03
              • 1970-01-01
              • 1970-01-01
              • 2012-02-12
              • 1970-01-01
              相关资源
              最近更新 更多