为什么我不必导入在Java中不用作变量类型的类?

时间:2013-07-09 15:40:19

标签: java class import

以下是一个例子:

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

5 个答案:

答案 0 :(得分:5)

  

我理解为什么第二个例子会出错,但为什么我第一个出错呢? java编译器如何知道map.keySet()返回的内容而不导入java.util.Set

它知道这两种方式 - 它是字节码中元数据的一部分。

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

来自section 7.5 of the JLS

  

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

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

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

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

写成:

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

就是这样。

答案 1 :(得分:2)

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

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

import使用类没有任何关系;它只影响你如何写出它的名字。

答案 2 :(得分:1)

java编译器知道map.keySet()返回的内容,因为它位于HashMap的定义中。

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

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

然后编译器将此信息放在已编译的类文件中,作为方法“签名”的返回类型。

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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