简体   繁体   English

当两个具有相同名称的类可用时,为什么我没有名称冲突?

[英]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.Stringorg.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.Stringorg.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? Stringjava.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 use java.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 the String 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.Listjava.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.

相关问题 当我们在Java中有两个具有相同名称的类时会发生什么? - what happens when we have two classes with same names in java? 两个类具有相同的 XML 类型名称 - Two Classes have same XML type name 当我尝试使用具有相同名称和参数类型的两个方法时,为什么会出现编译错误? - Why do I get a compilation error when I try to have two methods with the same name and parameter type? 为什么我不能有一个与其包含类同名的两级深度内部类? - Why can't I have a two-level-deep inner class with the same name as its containing class? 调用方法时不必使用相同的参数名称吗? - Don't you have to use the same parameter names when calling a method? 我可以为同一个变量使用两个名字吗? - Can I have two names for the same variable? BeanResult的BindingResult或普通目标对象都不能用作请求属性,我也不知道为什么 - Neither BindingResult nor plain target object for bean name available as request attribute, and I don't know why Joda Time类没有任何构造函数......为什么?我做错了什么? - Joda Time classes don't have any constructors… why? And what am I doing wrong? 为什么我不必导入在Java中不用作变量类型的类? - Why don't I have to import classes not used as variable types in Java? 为什么不是所有Java类都有接口? - Why don't all Java classes have interfaces?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM