Java类名与嵌套包名相同

时间:2012-03-06 12:52:38

标签: java package

在我的Java应用程序中,我使用的是第三方库。

然而,我发现了一些奇怪的东西,有一些嵌套的包,以及一些名称可能与包名相同的类。

恐怕我无法说清楚。这是一个例子:

  com.xx.a
  com.xx.a.a

还有一个名为' a'在' com.xx.a'。

所以如果我想打电话给这个班级' a' ...

我写道:

a ma = new com.xx.a.a();

然后IDE会认为我的意思是包' com.xx.a.a'。

然后我不能称之为。

我想知道为什么?

顺便说一句,图书馆提供者似乎不希望我们使用这些类。

他们是如何做到的?

5 个答案:

答案 0 :(得分:5)

Java语言允许类标识符被包标识符隐藏。在您的情况下, com.xx.a会被 com.xx.a遮挡。

来自Java Language Specification

  

6.3.2模糊声明

     

简单名称可能出现在可能被解释为变量名称,类型或的上下文中。在这些情况下,§6.5的规则指定将优先选择变量而不是类型,并且将优先选择类型而不是包。因此,有时可能无法通过其简单名称引用可见类型或包声明。 我们说这样的声明是模糊的。

我必须说§6.5中用于对标识符含义进行分类的规则远非明确。

您仍然碰巧拥有违反此规则的库副本的原因是因为该规则不适用于类文件/ JAR文件和JVM。

这意味着您可以在JAR文件中存在此类命名冲突,但您永远不会将其视为javac的输出。生成这些类/包名称的工具很可能是代码混淆器,它会生成这种混乱的代码来压缩文件的大小并混淆代码以防止逆向工程。


PS。仔细看看它实际上可能是Eclipse方面的一个错误(假设你正在谈论的是IDE)。通过让空包名与类名冲突,Eclipse会对javac接受的内容进行扼杀。规范很难遵循,但从我所看到的情况来看,javac在这种情况下遵循规范。

答案 1 :(得分:0)

你需要这样做:

com.xx.a.a ma = new com.xx.a.a();

或导入包:

import com.xx.a;

a ma = new a();

答案 2 :(得分:0)

库可能会被混淆(例如使用proguard)以减小尺寸,防止逆向工程和“隐藏”你不应该使用的东西。即使您设法创建此类的实例,我也会建议您反对它,因为您不知道它将做什么或如何使用它。

答案 3 :(得分:0)

我们不能在java中执行此操作:

com.xx.A
com.xx.A.yy

包名与父包中的类相冲突。

答案 4 :(得分:0)

这是反编译jar时的常见问题。 当有一个类和一个具有相同名称的子包时,编译器会感到困惑。如果找不到带有关于类型(包,类变量)的前缀的选项的编译器,则必须重构源文件。您可以使用regex执行此操作,例如重命名每个包声明并从中导入 import A.B.C 喜欢的东西 import pkgA.pkgB.C. 当然你不能对sdk或其他库中的外部包执行此操作,但大多数情况下使用的混淆器以相同的方式重命名它们,因此,为了重命名为A-Z中的字母,您可以使用类似的东西:

  

RegexFindAll(“进口\ S +(?:。[AZ] \ S * \ S *)*([AZ])\ S * \ S *(?:[AZ] \ S * \ S *)。 * [AZ] \ S *;“)

     

RegexFindAll( “?包\ S +(:([A-Z])\ S * \ S *)*([A-Z])\ S *;”)

从那以后,您可以重命名每个包裹。如果您的IDE不提供此类功能,您还可以使用以下命令来使用终端。

以递归方式按名称查找所有文件(可使用文件名过滤器扩展)

  来自https://stackoverflow.com/a/105249/4560817

find -follow

迭代找到的文件名

sudo find . -name *.mp3 |
while read filename
do
    echo "$filename"    # ... or any other command using $filename
done
  

来自https://stackoverflow.com/a/9391044/4560817

用正则表达式替换文件中的文本

  来自https://askubuntu.com/a/20416

sed -i 's/original/new/g' file.txt