【问题标题】:Java class name same as the nested package nameJava 类名与嵌套包名相同
【发布时间】:2012-03-06 12:52:38
【问题描述】:

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

但是,我发现了一些奇怪的东西,有一些嵌套的包,还有一些类的名字可能和包的名字一样。

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

包装

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

在 'com.xx.a' 中有一个名为 'a' 的类。

所以如果我想把这个类称为'a'......

我写:

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

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

那我就不能叫了。

不知道为什么?

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

他们是怎么做到的?

【问题讨论】:

    标签: java package


    【解决方案1】:

    Java 语言允许类标识符被包标识符模糊。在您的情况下,class com.xx.apackage com.xx.a 所掩盖。

    来自Java Language Specification

    6.3.2 模糊声明

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

    我必须说,第 6.5 节中对标识符含义进行分类的规则还很不明确。

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

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


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

    【讨论】:

    • 是不是说混淆是在class文件而不是.java源代码上做的?
    • 是的,如果他们使用标准的 Java 编译器,这正是它的意思。
    • 在当前版本的 JLS 中,在 §6.4.2 而不是 6.3.2 中指定了遮蔽,但更重要的是,遮蔽仅定义了如何解释 simple 名称。但是,com.xx.a 是限定名称,而不是简单名称。因此,模糊不适用。
    【解决方案2】:

    这是反编译 jar 时的常见问题。 当存在同名的类和子包时,编译器会感到困惑。如果你没有找到一个编译器可以选择附加关于类型(包,类变量)的前缀,你必须重构源文件。您可以使用正则表达式来做到这一点,例如重命名每个包声明并从 import A.B.C 类似于 import pkgA.pkgB.C. 当然,对于来自 sdk 或其他库的外部包,您不能这样做,但大多数情况下,使用的混淆器会以相同的方式重命名它们,因此对于重命名为 A-Z 中的字母,您可以使用以下内容:

    RegexFindAll("import\s+(?:[A-Z]\s*.\s*)*([A-Z])\s*.\s*(?:[A-Z]\s*.\s* )*[A-Z]\s*")

    RegexFindAll("package\s+(?:([A-Z])\s*.\s*)*([A-Z])\s*;")

    从那里你可以重命名每个包。如果您的 IDE 不提供此类功能,您也可以通过以下命令依赖终端。

    按名称递归查找所有文件(可通过文件名过滤器扩展)

    find -follow 来自https://stackoverflow.com/a/105249/4560817

    遍历找到的文件名

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

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

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

    sed -i 's/original/new/g' file.txt 来自https://askubuntu.com/a/20416

    【讨论】:

      【解决方案3】:

      你需要这样做:

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

      或者导入包:

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

      【讨论】:

        【解决方案4】:

        该库可能会被混淆(例如使用 proguard)以减小大小、防止逆向工程和“隐藏”您不应该使用的内容。即使您设法创建了此类的实例,我也建议您不要这样做,因为您不知道它会做什么或如何/应该如何使用它。

        【讨论】:

        • 连代码都被混淆了,但我想知道为什么它可以工作?正如simaremare所说,我们不能在java中这样做,所以我想知道是否对生成的类文件进行了混淆?
        【解决方案5】:

        我们不能在 java 中这样做:

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

        包名与父包中的类冲突。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-24
          • 1970-01-01
          • 2011-06-11
          • 2020-03-20
          相关资源
          最近更新 更多