为什么Java编译器会抱怨显式导入名称冲突而不是导入包。*?

时间:2014-03-27 04:48:58

标签: java

以下代码编译并正确运行。

import java.util.*;
import java.io.*;



class Scanner {
    public Scanner(InputStream in) {

    }
}
public class Foo{
    public static void main(String[] args) {
        java.util.Scanner in = new java.util.Scanner(System.in);
        System.out.println(in.getClass());

        Scanner in2 = new Scanner(System.in);
        System.out.println(in2.getClass());
    }
}

但是,如果我将import java.util.*;更改为import java.util.Scanner;,我将收到以下编译错误。

Foo.java:1: error: Scanner is already defined in this compilation unit

似乎在这两种情况下,编译器都应该能够同样消除歧义,那么为什么它只会在第二种情况下抱怨?

4 个答案:

答案 0 :(得分:5)

这将发生,因为您已经有一个名为Scanner的本地类。您需要使用其完全限定名称来调用它:

java.util.Scanner scan = new java.util.Scanner(System.in);

此外,将Scanner设为嵌套静态类:

public class Foo {

    private static class Scanner {

        public Scanner(InputStream in) {

        }
    }

    public static void main(String[] args) {
        java.util.Scanner in = new java.util.Scanner(System.in);
        System.out.println(in.getClass());

        Scanner in2 = new Scanner(System.in);
        System.out.println(in2.getClass());
    }
}

为什么会发生这种情况

import只是告诉编译器在编译时在哪里查找符号。我不记得我头顶的阶段(预处理/编译),但包导入不是这些类成员的显式声明。通过说import foo.bar.*,你说"在编译"时在这个包目录中查找符号,而import foo.bar.Scanner说"点Scanner符号到这个&# 34。

简而言之,一个特定的导入显然是你有#34; Scanner"的符号,而包导入没有指定这个特定的符号关系。

答案 1 :(得分:2)

为什么导入java.util.*不会出错?

它不会引发错误,因为没有关于“java.util.Scanner”类和您的班级Scanner的混淆。

当您将导入用作java.util.Scanner时,它会与Scanner中的util与您的班级名称冲突。

这就是出错的原因。

答案 2 :(得分:0)

单一类型导入声明与顶级类型声明的冲突在JSL §7.5.1. Single-Type-Import Declarations中描述:

  

如果单一类型导入声明导入其简单名称的类型   是n,编译单元也声明了顶级类型(§7.6)   其简单名称为n,发生编译时错误。

§7.5.1

引用的一个例子
import java.util.Vector;
class Vector { Object[] vec; }
由于Vector的重复声明,

导致编译时错误。

答案 3 :(得分:0)

当您的java类名和导入库名相同时,会发生这种情况。在您的情况下,Scanner是指类名而不是库。将类名更改为其他名称将是解决错误的最简单方法。