将类名称作为字符串,如何在运行时获取它的包名?我没有包名+类名的完全限定名。只是类名。
我希望在Class.forName()
方法中使用包名称。
我很满意找到第一个匹配的包名(如果多个包具有相同的类)。
有什么想法吗?
更新
我没有要处理的Class实例。我的要求是使用Class.forName()
方法创建一个类。但我只是将类名作为字符串。我需要一些方法来循环包,并确定我所属的类是否属于包。
异常的堆栈跟踪是
Exception in thread "main" java.lang.ClassNotFoundException: MyAddressBookPage
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
答案 0 :(得分:10)
这很可能是一种非常低效,臃肿,不方便的方式来做你想要实现的目标,并且希望已经有一种开箱即用的单一方式来做到这一点......但它应该有效
基本上,浏览类路径中的每个类,直到找到getSimpleName()
与您的类名匹配的类。
我建议查看Google Classpath Explorer以帮助管理这样做的具体细节。
看起来像这样:
ClassPath classpath = new ClassPathFactory().createFromJVM();
RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter(".*", ".*\\.class");
String[] resources = classpath.findResources("", regExpResourceFilter);
resources
是一个字符串数组,如'com / foo / bar / Baz.class'。你现在可以简单地遍历并找到匹配的条目,并将它们从斜线转换为点线,去掉'.class'等。只要小心尝试匹配内部类,因为它们中将包含'$'字符。
另外,据我所知,这将 NOT 导致加载这些类。
答案 1 :(得分:8)
final Package[] packages = Package.getPackages();
final String className = "ArrayList";
for (final Package p : packages) {
final String pack = p.getName();
final String tentative = pack + "." + className;
try {
Class.forName(tentative);
} catch (final ClassNotFoundException e) {
continue;
}
System.out.println(pack);
break;
}
答案 2 :(得分:3)
唯一的方法是导航类路径中的目录/ jar和带有类名的条目。
这是一些几乎可以满足您需求的代码。此代码是我所拥有的类的一部分,用于搜索用于创建接口实例的实现/工厂方法。抱歉,没有时间更改它以查找命名类,应该是一个简单的更改,正如我在其他地方提到的那样,您不需要加载类,只需检查名称。
public Class<?> locateImplementation(Class<?> type) {
Class<?> c = null;
String[] cp = System.getProperty("java.class.path").split(File.pathSeparator);
for (int i = 0; (c == null) && (i < cp.length); ++i) {
File f = new File(cp[i]);
if (f.exists() && f.canRead()) {
if (isJar(f)) {
try {
c = searchJar(type, new FileInputStream(f));
} catch (Throwable t) {
// Nothing to worry about
}
} else {
c = searchFile(type, f);
}
}
}
return c;
}
private boolean isClass(String path) {
return path.matches(".+\\.class$") && !path.contains("$");
}
private Class<?> searchFile(Class<?> type, File f) {
return searchFile(type, f, f.getPath());
}
private Class<?> searchFile(Class<?> type, File f, String root) {
Class<?> implementation = null;
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
implementation = searchFile(type, files[i], root);
if (implementation != null) {
break;
}
}
} else if (isClass(f.getPath())) {
String path = f.getPath().substring(root.length() + 1);
Class<?> c = getClass(path);
if ((c != null) && !c.isInterface() &&
type.isAssignableFrom(c)) {
implementation = c;
}
}
return implementation;
}
private Class<?> getClass(String name) {
Class<?> c;
String className = name.replaceAll("[/\\\\]", ".")
.replaceFirst("^\\.", "").replace(".class", "");
try {
c = Class.forName(className);
} catch (Throwable e) {
c = null;
}
return c;
}
private Class<?> searchJar(Class<?> type, InputStream in)
throws Exception {
ZipInputStream zin = new ZipInputStream(in);
Class<?> implementation = null;
ZipEntry ze;
while ((implementation == null)
&& ((ze = zin.getNextEntry()) != null)) {
String name = ze.getName();
if (name.endsWith("class")
&& name.matches("^com.xxx.+")
&& !name.contains("$")) {
try {
Class<?> c = getClass(name);
if ((c != null) && !c.isInterface()
&& type.isAssignableFrom(c)) {
implementation = c;
}
} catch (Throwable t) {
// Nothing to worry about
}
}
}
return implementation;
}
private boolean isJar(File f) {
return f.getPath().endsWith(".jar");
}
答案 3 :(得分:0)
最简单的解决方案之一:
Test.class.toString().replace("class", "").replace(".","/").replace(" ", "")
答案 4 :(得分:0)
在类上调用getPackageName()。它返回完全限定的包名称。此外,值得一提的是,这是Java 9的一项功能。