简体   繁体   中英

Why don't I have to import classes not used as variable types in Java?

Here is an example:

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());
    }
}

Everything compiles and runs fine. However, when I move map.keySet() to another variable:

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());
    }
}

I get an error thrown at me:

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

I understand why I get an error for the second example, but why don't I get an error for the first? How does the java compiler know what map.keySet() returns without importing java.util.Set?

I've seen this behavior in other programming languages too, notably C++.

I understand why I get an error for the second example, but why don't I get an error for the first? How does the java compiler know what map.keySet() returns without importing java.util.Set ?

It knows that either way - it's part of the metadata in the bytecode.

What it doesn't know is what you mean by Set<String> . An import just changes the meaning of a name in your source code - and that name doesn't appear in your source code in the first piece of code.

From section 7.5 of the JLS :

An import declaration allows a named type or a static member to be referred to by a simple name (§6.2) that consists of a single identifier.

You don't refer to the simple name in your first example, so the benefit described above is irrelevant.

To put it another way, the import just allows this line (which would be valid in your second sample):

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

to be written as:

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

That's all it does.

The import directive is a purely syntactic feature which allows you to refer to a type without qualifying it with the package name.

Since your first code never refers to a the Set type, it works fine without the import.

import has nothing to do with using a class; it only affects how you can write its name.

The java compiler knows what map.keySet() returns because it is in the definition of HashMap .

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

When HashMap was compiled, the compiler knew what was Set<> because there was an import statement in the source of HashMap for that (or rather, in that case, no import statement was needed because Set is in the same package as HashMap).

Then the compiler put this information in the compiled class file, as the return type of the "signature" of the method.

When you are using map.keySet() , you don't have to specify the return type of the method because the compiler has access to the class file of HashMap and therefore it knows all it needs.

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

In the first case, the type of map.keySet() is known. The return type is part of the contract of the method.

In the second case, the unqualified name Set is not enough to identify the type of the variable keys . The fully qualified type name is not inferred from the right-hand-side of the assignment. You can either fully qualify the name, or import it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM