2013-07-09 59 views
2

下面是一個例子:爲什麼我不必在Java中導入不用作變量類型的類?

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

我明白爲什麼我在第二個例子中出現錯誤,但爲什麼我沒有得到第一個錯誤? 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(); 

這就是它。

2

import指令是一個純粹的語法功能,它允許您引用一個類型而不用包名限定它。

由於您的第一個代碼永遠不會引用Set類型,因此無需導入即可正常工作。

import無關使用一類;它隻影響你如何寫它的名字。

0

因爲在第一個例子中,keySet()在HashMap對象中執行,而不是在你的main中,這就是爲什麼你不需要聲明它。

0

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

在第二種情況下,不合格名稱Set不足以識別變量keys的類型。完全限定類型名稱不是從作業的右側推斷出來的。您可以完全限定名稱,或導入它。

1

java編譯器知道map.keySet()返回什麼,因爲它在HashMap的定義中。

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

當HashMap的編譯,編譯器知道什麼是Set<>,原因是在HashMap中的該源的import聲明(或者更確切地說,在這種情況下,是不需要導入語句,因爲設置在同一包作爲HashMap)。

然後編譯器將這些信息放入編譯後的類文件中,作爲方法「簽名」的返回類型。

當您使用map.keySet()時,您不必指定方法的返回類型,因爲編譯器可以訪問HashMap的類文件,因此它知道它所需的全部內容。

相關問題