[英]Why I don't have a clashing name conflict when two classes with same names are available?
Let's say I have a:假设我有一个:
package org.something.a;
public class String {
...
}
and和
package org.something.a;
public class Main {
public static void main(String[] args) {
String a = new String(); //IDE shows that this is a org.something.a.String type and not java.lang.String
System.out.println(a.getClass().getName());
}
}
I wonder why there's no name clash for String
, as java.lang.String
and org.something.a.String
are both available in a org.something.a
package, on a compile-time class-path, and why custom-defined class ( org.something.b
) has a preference, as IDE (IntelliJ) resolves String
to org.something.a.String
?我想知道为什么String
没有名称冲突,因为java.lang.String
和org.something.a.String
在编译时类路径上的org.something.a
package 中都可用,以及为什么自定义class ( org.something.b
) 有偏好,因为 IDE (IntelliJ) 将String
解析为org.something.a.String
?
Besides, if I'll compile both files with javac *.java
and then invoke java Main
, I get this:此外,如果我用javac *.java
编译这两个文件,然后调用java Main
,我得到这个:
Error: Main method not found in class Main, please define the main method as: public static void main(String[] args)报错:Main method not found in class Main,请将main方法定义为:public static void main(String[] args)
but if I change the main method signature to:但是如果我将主要方法签名更改为:
public static void main(java.lang.String[] args) {...}
then it compiles and prints String
.然后它编译并打印String
。 Which means, it then compiles entire file having imported java.lang.String
and it failed before because, main
method didn't have a java.lang.String
array as a parameter.这意味着,它然后编译导入java.lang.String
的整个文件,之前它失败了,因为main
方法没有java.lang.String
数组作为参数。
I am well aware of this: JLS §7 :我很清楚这一点: JLS §7 :
Code in a compilation unit automatically has access to all classes and interfaces declared in its package and also automatically imports all of the public classes and interfaces declared in the predefined package java.lang.编译单元中的代码自动访问其 package 中声明的所有类和接口,并自动导入预定义 package java.lang 中声明的所有公共类和接口。
and as far as I remember, this must be a name clash.据我所知,这一定是名字冲突。 But even if it's not, the behaviour above is really unclear - why custom class has a preference and why everything changes if I just append java.lang
to the main method's parameter.但即使不是,上面的行为也确实不清楚 - 为什么自定义 class 有偏好,为什么如果我只是 append java.lang
到主要方法的参数,一切都会改变。
Cannot find any appropriate spec page in JLS.在 JLS 中找不到任何合适的规范页面。
6.3 Scope of a Declaration states: 6.3 Scope 声明指出:
The scope of a top level class or interface (§7.6) is all class and interface declarations in the package in which the top level class or interface is declared.顶层 class 或接口(§7.6)的 scope 是所有 class 和 package 中的接口声明,其中声明了顶层 class 或接口。
Then why does org.something.a.String
not clash with java.lang.String
, since java.lang.*
is imported into every compilation unit?那么为什么org.something.a.String
不与java.lang.String
冲突,因为java.lang.*
被导入每个编译单元?
7.3 Compilation Units states: 7.3 编译单元声明:
Every compilation unit implicitly imports every public class or interface declared in the predefined package java.lang, as if the declaration
import java.lang.*;
每个编译单元隐式导入每个公共 class 或在预定义 package java.lang 中声明的接口,就好像声明import java.lang.*;
appeared at the beginning of each compilation unit immediately after any package declaration.在任何 package 声明之后立即出现在每个编译单元的开头。 As a result, the names of all those classes and interfaces are available as simple names in every compilation unit.因此,所有这些类和接口的名称在每个编译单元中都可以作为简单名称使用。
Note that it explicitly states the import statement as import java.lang.*;
请注意,它明确地将导入语句声明为import java.lang.*;
, which is called an "import on demand": ,这被称为“按需导入”:
7.5.2 Type-Import-on-Demand Declarations 7.5.2 Type-Import-on-Demand 声明
A type-import-on-demand declaration allows all accessible classes and interfaces of a named package, class, or interface to be imported as needed.按需类型导入声明允许根据需要导入命名为 package、class 或接口的所有可访问类和接口。
TypeImportOnDemandDeclaration: import PackageOrTypeName. *;
And 6.4.1 Shadowing says about import-on-demand: 6.4.1 Shadowing谈到按需导入:
A type-import-on-demand declaration never causes any other declaration to be shadowed.按需类型导入声明永远不会导致任何其他声明被隐藏。
Therefore java.lang.String
can never shadow a class named String
(and similar for other classes from java.lang
)因此java.lang.String
永远不能隐藏一个名为 class 的String
(对于java.lang
中的其他类也类似)
With the two classes有了这两个班级
package org.something.a;
class String {}
public class Main {
public static void main(String[] args) {
String a = new String(); //IDE shows that this is a org.something.a.String type and not java.lang.String
System.out.println(a.getClass().getName());
}
}
you cannot run org.something.a.Main
because that main
method has a signature of public static void main(org.something.a.String[] args)
, but to be able to run that class the signature must be public static void main(java.lang.String[] args)
.你不能运行org.something.a.Main
因为那个main
方法的签名是public static void main(org.something.a.String[] args)
,但是为了能够运行那个 class 签名必须是public static void main(java.lang.String[] args)
。 Note the most of the times you can just write the method as public static void main(String[] args)
because there is no class String
in the current package that shadows java.lang.String
.请注意,大多数时候您可以将方法编写为public static void main(String[] args)
因为当前 package 中没有 class String
隐藏java.lang.String
。
If you change your code to如果您将代码更改为
package org.something.a;
class String {}
public class Main {
public static void main(java.lang.String[] args) {
String a = new String(); //IDE shows that this is a org.something.a.String type and not java.lang.String
System.out.println(a.getClass().getName());
}
}
then you will be able to run that class because now the signature of the main method is correct.那么您将能够运行 class 因为现在 main 方法的签名是正确的。
Running this code will output运行此代码将 output
org.something.a.String
To see the difference between java.lang.String
and org.something.a.String
you should expand your main
method to要查看java.lang.String
和org.something.a.String
之间的区别,您应该将main
方法扩展为
package org.something.a;
class String {}
public class Main {
public static void main(java.lang.String[] args) {
String a = new String(); //IDE shows that this is a org.something.a.String type and not java.lang.String
System.out.println("a has class " + a.getClass().getName());
System.out.println("args has class " + args.getClass().getName());
System.out.println("args has component type " + args.getClass().componentType().getName());
java.lang.String b = new java.lang.String();
System.out.println("b has class " + b.getClass().getName());
}
}
which will output这将 output
a has class org.something.a.String args has class [Ljava.lang.String; args has component type java.lang.String b has class java.lang.String
How does the mapping of String
to java.lang.String
disappear? String
到java.lang.String
的映射是怎么消失的?
It doesn't disappear, it doesn't manifest itself in the first place.它不会消失,它不会首先显现出来。
It is important to understand that all those import statements are a mere convenience feature for us lazy programmers.重要的是要理解所有这些 import 语句对于我们懒惰的程序员来说只是一个方便的功能。
A single-type-import statement of the form import java.util.List;
形式为import java.util.List;
lets us tell the compiler:让我们告诉编译器:
Look, anytime I write
List
as a simple, unqualified class name I want you to usejava.util.List
as the qualified class name.你看,只要我将List
写成一个简单的、不合格的 class 名称,我希望你使用java.util.List
作为合格的 class 名称。
This import statement doesn't prevent you from using the class java.awt.List
- it just means that you always have to use the fully qualified class name java.awt.List
if you want to use that specific class. And it doesn't change a bit for the compilation process - the compilation process internally always only ever uses the fully qualified class names.此导入语句不会阻止您使用 class java.awt.List
- 它只是意味着您始终必须使用完全限定的 class 名称java.awt.List
如果您想使用特定的 class。它不会编译过程没有一点改变——内部编译过程总是只使用完全限定的 class 名称。
An import-on-demand statement of the form import java.lang.*;
import java.lang.*;
which is implicitly the first import statement of every compilation unit is even more lazy.这隐含地是每个编译单元的第一个 import 语句更加懒惰。 It tells the compiler:它告诉编译器:
Look, anytime I write
String
as a simple, unqualified class name and you cannot find the definition of theString
class neither in the current package nor in a single-type-import statement, look in all those packages that are imported on demand whether you can find such a class in any of those packages.看,任何时候我将String
写成一个简单的、不合格的 class 名称,而您在当前 package 或单一类型导入语句中都找不到String
class 的定义,请查看所有按需导入的包,无论您是否可以在任何这些包中找到这样的 class。 And if you can find exactly one such class there use that's class fully qualified class name.如果您能准确找到一个这样的 class,请使用 class 完全限定的 class 名称。
For completeness: the reason why I wrote if you can find exactly one such class is this: nobody prevents you from writing为了完整起见:如果你能找到一个这样的 class ,我写信的原因是:没有人阻止你写
import java.awt.*;
import java.util.*;
And the compiler will still happily compile your code - until the moment where you try to use the simple class name List
.并且编译器仍然会愉快地编译您的代码 - 直到您尝试使用简单的 class 名称List
的那一刻。 As soon as you try to use both import statements and the simple class name List
the compiler will abort with an error because with those two import statements it cannot know whether you want the class name List
to refer to java.awt.List
or to java.util.List
.一旦您尝试同时使用 import 语句和简单的 class name List
,编译器将因错误而中止,因为对于这两个 import 语句,它无法知道您是否希望 class name List
引用java.awt.List
或java.util.List
.列表。
In your case (where the class String
is in the same package as the class Main
) this reason doesn't apply.在您的情况下(其中 class String
与 class Main
位于同一 package 中)此原因不适用。 There is no implicit import org.something.a.*
.没有隐式import org.something.a.*
。
** if java.lang.String
never shadows, then where does it go..** ** 如果java.lang.String
从不隐藏,那么它在哪里 go..**
java.lang.String
is always there. java.lang.String
始终存在。 It is only the simple name String
that no longer means java.lang.String
but refers to the class String
from the current package.只是简单的名字String
不再表示java.lang.String
,而是从当前的package指代class String
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.