检查特定包中是否存在类



我需要检查包中是否存在类。我知道我可以使用Class.forName来检查类是否存在,但我如何验证它是否在特定的包中?

不要为此使用class.forName

Class.forName采用完全限定的名称。完全限定的名称包括包,但也包括外部类,因此,在这里不起作用:

package pkg;
class Outer {
class Inner {}
}

结果是完全限定的名称,即必须传递给CFN的名称,对于Inner是:Class.forName("pkg.Outer.Inner");-以及如何告诉Outer是外部类而不是包名称的一部分?

Java不具有分层包;pkgpkg.subpkg之间没有关系,所以您的问题希望不会涉及"如何检查包部分是否以特定字符串开始",因为您不应该在java生态系统中问这个问题。

因此,让我们离开Class.forName.

请注意,该类需要在运行时可用,否则将无法工作"幸运的是";,如果该类在运行时不可用,并且您希望确定给定的包(例如,一个完全限定的类名),由于外部和内部类的上述问题,这项工作实际上是不可能的,所以如果这就是您的问题的根源,您可以停止阅读:No can do。让我们假设在运行时可用。

您需要一个Class<?>对象

每个类都由一个java.lang.Class<?>类型的对象表示。你需要获得这样一个对象,然后你可以确定它在哪个包中。

策略1:Class.forName

Class.forName("pkg.Outer.Inner")将为您带来课程<gt;对象,从那里你可以问它的包是什么,得到pkg,你可能想知道。因此,这是一种方法:给定一个表示类的完全限定名称的字符串,将其抛出Class.forName,然后对由此得到的class对象进行操作。

策略2:课堂文字

Java有特殊的语法来获得给定类型引用的Class<?>对象。所以,如果你在写代码时知道类型引用,你可以使用这个:

package pkg;
class Outer {
class Inner{}
private static Class<?> innerClassObj = Inner.class;
}

然而,如果您可以这样写,那么在编写时您就已经知道该类来自哪个包,所以这使得您的问题完全没有意义。为什么要在运行时找出你已经知道的东西?

万一这是你想知道的:检查你的导入,在任何主要的IDE中,按住CMD(非Mac上的CTRL),然后单击名称,它会带你到定义它的地方,包就会在那里列出。或者只是浮在上面,这在大多数IDE中也同样有效。

策略3:从对象实例

所有对象都有一个.getClass()方法,该方法获得代表对象创建方式的Class<?>实例。

不过要小心

List<String> list = new ArrayList<String>() {
@Override public boolean add (String other) {
log.info("Added: {}", other);
return super.add(other);
}
};

这是非常有效的、有点常见的、完全无辜的java代码。然而,这意味着现在调用list.getClass(),然后询问该类的名称,会得到类似com.foo.internal.WhateverClassThatCodeShowedUpIn$1的东西,因为从技术上讲,这是一个子类,因此list就是它的一个实例。如果您想检查对象是否是"来自java.util包的类",那么只看list.getClass()就会错误地告诉您它不是。

解决方法是要意识到这一点,并始终(在while循环中)遍历所有超类。list.getClass().getSuperclass()将解析为与java.util.ArrayList.class完全相同的实例,调用上的getSuperclass将获得java.util.AbstractList.class,然后是java.lang.Object.classnulljava.util.List.class从未出现在这里——那不是一个类,那是一个接口。如果你也想要这些,那么.getInterfaces()就存在了。

所以,如果你想知道:这个对象与某个特定包中的某个类兼容吗?这就是你的答案。唯一的方法是使用while循环(若要检查接口,甚至可以使用队列或递归方法)。

策略4:把它给你

您总是可以有一个方法,将Class<?>作为参数。各种各样的API也为您提供了一个。

好吧,我有一个Class<?>实例,现在怎么办

您可以在上面调用.getPackage()方法,但不幸的是,JVM规范规定这实际上不必返回一些东西(它可能返回null)。所以这不是一个好的解决方案。相反,我建议您在它上调用.getName(),然后使用您得到的字符串进城。

你得到的字符串应该是pkg.Outer$Inner。您可以看到如何从以下内容中导出包:

  1. 查找最后一个.
  2. 如果它存在,就把它和它之后的一切都去掉
  3. 如果根本没有点,它就在未命名的包中

沃伊拉。那就剩下pkg了。

注意:考虑到策略3中所写的内容:为了满足您的需求,您可能必须递归地扫描超类和所有超接口。

最新更新