如何访问默认包中的Java类?

109

我现在正在一个grails项目中与他人合作工作。 我需要编写一些Java类,但是我需要访问使用groovy创建的可搜索对象。 看起来,此对象必须放置在默认包中。

我的问题是: 有没有办法从命名包中的Java类访问默认包中的这个对象?

5个回答

135

你不能从命名包中使用默认包中的类。
从技术上讲,你可以通过反射API,如Sharique Abdullah的答案所示,但是未命名命名空间中的类在导入声明不在作用域内

在J2SE 1.4之前,你可以使用以下语法导入默认包中的类:

import Unfinished;

这已经不再被允许了。因此,要从一个打包类中访问默认包类,需要将默认包类移动到自己的包中。

如果您可以访问由Groovy生成的源代码,则需要进行一些后处理,将文件移动到专用包中,并在其开头添加这个"package"指令。


更新2014年:bug 6975015,适用于JDK7和JDK8,对于从未命名的包中导入的限制更加严格。

TypeName必须是类类型、接口类型、枚举类型或注解类型的规范名称。
该类型必须是一个命名包的成员,或者是一个最外层的词法封闭类型是一个命名包的成员,否则会发生编译时错误。


Andreas在评论中指出:

“为什么[默认包]一开始就存在?是设计错误吗?”

不,这是有意为之。
JLS 7.4.2. 无名包中提到:“无名包主要是为了方便开发小型或临时应用程序,或者刚开始开发时使用。”


7
我曾向其他人解释过,Java世界中默认包是二等公民,请不要这样做。 :-) - C. K. Young
1
看来我必须在时间非常紧张的项目中学习Groovy,或者在默认包中编写代码。 :-( - Mnementh
11
如果是这样,那么为什么一开始会有这个问题呢?是设计错误吗? - Pacerier
@VonC 是的,这就是我的意思。 - Suzan Cioc
1
@Pacerier "为什么默认包会存在?是设计错误吗?" 不,这是故意的。JLS 7.4.2. 未命名包 表示:"未命名包主要是为了方便开发小型或临时应用程序或者刚开始开发"而由Java SE平台提供的。 - Andreas
显示剩余13条评论

63

实际上,你可以。

使用反射API,你可以访问到目前为止的任何类。至少我能做到 :)

Class fooClass = Class.forName("FooBar");
Method fooMethod = fooClass.getMethod("fooMethod", String.class);

String fooReturned = (String)fooMethod.invoke(fooClass.newInstance(), "I did it");

对于Scala,以下代码有效:val bar = "hi"; val fooClass = Class.forName("FooClass"); val fooMethod = fooClass.getMethod("foo", classOf[Array[String]]); val fooReturned = fooMethod.invoke(fooClass.newInstance(), Array(bar)); - Jus12
2
很棒的答案,+1。由于问题是关于 Groovy 的,您可以使用鸭子类型(就像使用胶带一样)... Class.forName("FooBar").newInstance().fooMethod("I did it") - Bill K
1
如果我有两个名为FooBar的类来自于两个不同的jar文件,哪一个会被调用? - Davide

7
使用 jarjar 工具重新打包 jar 文件,并按照以下规则进行操作:
rule * <target package name>.@1

源jar文件中默认包中的所有类将移动到目标包中,因此可以访问。


4
展示如何使用JarJar的演示将是很好的。 - BiGGZ
@BiGGZ:请参阅jarjar github仓库中的README.md文件,以了解如何在ant、gradle或命令行中使用jarjar。 - lucidiot

3
你可以在 Groovy 代码中使用包,一切都会正常工作。这可能意味着需要在 grails-app 下进行轻微的代码重组,并且一开始可能有点麻烦,但是对于大型 grails 项目来说,将事物组织成包是有意义的。我们使用 Java 标准的包命名约定:com.foo.<app>.<package>
如果所有内容都在默认包中,那么它会成为集成的障碍,就像你现在遇到的问题一样。
控制器似乎是抵制放在 Java 包中的唯一 Grails 工件(或 artefact)。也许我还没有弄清楚那个 Convention。;-)

1

只是为了完整说明:

从内部 default-package,您可以访问驻留在命名包中的对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接