Java 或 C# 中的命名空间污染是否存在(如 C++)?

2022-09-03 07:41:45

我对Java和C#如何处理命名空间的概念感到困惑。

首先,一些编程语言中的命名空间污染示例:

  1. using namespace std对于C++。

    业界的每个人都对此感到不满,但初学者在开始编程时仍然被教导这样做。下面是一个关于处理全局命名空间的建议的 SO 问题

  2. import math.*在 Python 中

在上Python课时,我被告知不建议这样做,因为它会污染命名空间,并且首先允许访问数学库中的所有方法,而不会在编写具有重复名称的方法时引起冲突。它显然也会导致解释器的更多工作,因为它导入了所有函数,甚至是那些未使用的函数。Math.functionname

  1. 在 Ocaml 中打开模块 在 toplevel 或 ML 文件中执行此操作也可能导致命名冲突。特别是在编写库时。

  2. JavaScript 命名空间污染

问题:

C#和Java中是否存在“命名空间污染”(即导入大量在编写方法时可能导致冲突的方法)(它们在很多方面都很相似)?为什么不呢?

当然,相关问题太相似了,不能问另一个问题:

-是因为也许我们必须明确地做事还是有某种预防措施?@Override

-或者它存在,但它不是一个东西,因为它不会像“使用命名空间std”那样造成太大的破坏,而且我不知道它对学术课上的软件开发相对较新?

我发现自己在C#中有很多库,以避免必须为变量重新键入命名空间,例如usingXElement

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//the ones above are auto-generated by Visual Studio, too

using System.Xml.Linq;

将避免我每次创建XElement时都必须这样做。就像我们总是要做的一样C++System.Xml.Linq.XElementstd::cout

或者在Java中,我经常看到:,甚至import java.util.linkedlistimport java.util.*

如果我的类在其他地方使用,它们不会造成命名空间污染吗?还是因为它们只会“污染”该特定类范围,而不会在可能导入或继承我的类的其他类中”

我试图搜索答案,但找不到答案,我可能错误地表达了搜索。

编辑 4/20/2015

正如@RealSkeptic所提到的,事实证明,Java通配符导入也不鼓励。

除了下面接受的答案和答案之外,Java 和 C# 中的导入都包含在它们自己中,因此即使有人使用通配符类型的导入将未使用的方法名称添加到命名空间,它也不会影响其他类。在类级别,如果确实发生名称冲突,Java 和 C# 编译器将引发错误,引用不明确的导入,并且无法进一步编译,直到问题得到解决(例如,通过重命名函数)。


答案 1

正如其他人已经指出的那样,命名空间污染的问题在Java中并不像在C++中那样突出。命名空间污染之所以是C++问题(因此首先称为“污染”),主要是因为它可能会导致其他模块中的错误。这在为什么“使用命名空间 std;”被认为是不好的做法?“中有更详细的解释。

(这里令人担忧的是,这可能不仅指编译错误:对于编译错误,您被迫做一些事情并解决歧义。真正令人担忧的是,它可能会导致代码仍然正确编译,但之后只需调用错误的函数!


在Java中,每个都只影响包含它的文件。这意味着上述污染仍然可以在一个文件中本地发生。(可以说:只有作者的问题才真正造成了命名空间污染,这很公平)import

类似于上面提到的链接中的情况:假设你正在使用两个库,“foo”和“bar”。出于懒惰(或缺乏最佳实践知识),您正在使用通配符导入:

import foo.*:
import bar.*:

class MyClass {
    void someMethod() {

        // Assume that this class is from the "foo" librariy, and the
        // fully qualified name of this class is "foo.Example"
        Example e = new Example();
    }
}

现在想象一下,您升级了“bar”库的版本。新版本包含一个名为 .然后上面的代码将无法编译,因为对类的引用是不明确的。bar.ExampleExample

顺便说一句,静态导入也会出现同样的问题。它更加微妙和微妙,碰撞的可能性更大。这就是为什么他们说你应该非常谨慎地使用静态导入。


附注:当然,这些冲突和歧义可以很容易地解决。您始终可以改用完全限定的名称。大多数现代 Java IDE 都提供了组织/优化导入的功能。例如,在 Eclipse 中,您始终可以按 ++,这将(取决于 Preferences->Java->Code Style->Organize Imports)中的设置将所有通配符导入替换为单独的通配符导入。CTRLShiftO


答案 2

我认为Java / C#与C++有不同的哲学。让我解释一下。

当您在Java中导入某些内容时,您只是在代码的这一部分中导入它。假设您在包中有一个类。此外,在包中导入类并导入 。在C++中,将包含要使用的头文件,而在此头文件中,您将有一个.因此,将在 中可见。在Java中,情况并非如此:类必须包含它才能使用它。也就是说,您仍然可以获得命名空间污染,但它们更本地化(通常是每个文件)。这就是为什么在使用时应避免使用星号的原因。ApackageAABpackageBBjava.util.LinkedListAB#includeLinkedListLinkedListAAjava.util.LinkedListimport

我不能给C#一个合格的答案,因为我不使用它,但我认为他们的哲学是相似的。


推荐