2

这是一个例子:

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++。

4

5 回答 5

5

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

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

它不知道的是你的意思Set<String>。导入只会更改源代码中名称的含义——并且该名称不会出现在源代码的第一段代码中。

JLS 的第 7.5 节

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

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

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

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

可写为:

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

这就是它所做的一切。

于 2013-07-09T15:43:40.287 回答
2

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

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

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

于 2013-07-09T15:43:33.243 回答
1

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

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

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

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

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

于 2013-07-09T15:46:39.127 回答
0

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

于 2013-07-09T15:44:06.263 回答
0

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

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

于 2013-07-09T15:44:19.697 回答