我如何知道一个 class 是否是另一个的超 class,因为我只有 classes 的完全限定名称作为字符串?
How do I know if one class is superclass of another, given that I only have the fully qualified names of the classes as strings?
我需要知道一个字符串表示的 class 是否超class(直接或传递)另一个 class 也表示为字符串。例如:
String class1 = "java.lang.Object";
String class2 = "java.lang.Exception";
assertTrue( isSuperclass( class1, class2 ) );
我试图获取第二个 class 的 IType 并检查它的超级class名称。我就是这样尝试的:
/**
* Checks if class1 is directly or transitively superclass of class2.
*/
private boolean isSuperclass(final String class1, final String class2)
{
try
{
String className = class2;
while (className!=null)
{
final IType type = this.javaProject.findType(className);
if (type == null)
{
break;
}
className = type.getSuperclassName();
if (class1.equals(className))
{
return true;
}
}
return false;
}
catch (final JavaModelException e)
{
throw new IllegalStateException(e);
}
}
问题是 getSuperclassName return 只是 class 名称,而不是它的完全限定名称。出于这个原因,我不能在循环中再次调用 javaProject.findType 来检查 class2 的任何传递 superclass 是否等于 class1.
所以如果我调用:
isSuperclass( "java.lang.Throwable", "my.exceptions.Exception" )
它将 return 为假,因为
javaProject.findType("my.exceptions.Exception").getSuperclassName()
return只"ParentException",那么下次调用会是
javaProject.findType("ParentException")
其中 return 是空 IType,因为它不是 class 完全限定名称。这仅发生在正在分析的自己的应用程序中声明的 classes; for API classes getSuperclassName returns 完全限定名称。
我也考虑过通过 ITypeBindings 检查 isSuperclass,但我不知道如何从完全限定名称字符串或 IType 中获取 ITypeBinding。
关于如何检查 class 是否是另一个的超级class 的任何想法?
编辑:基于 Class.forName 的解决方案不适用于我的上下文。
如果你实际上可以加载有问题的类,你可以使用Class#isAssignableFrom
:
Class c1 = Class.forName(class1);
Class c2 = Class.forName(class2);
if (c1.isAssignableFrom(c2)) {
// c1 is a superclass or superinterface of c2
}
来自文档:
public boolean isAssignableFrom(Class<?> cls)
Determines if the class or interface represented by this Class
object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class
parameter. It returns true
if so; otherwise it returns false
.
例如:
String class1 = "java.lang.Object";
String class2 = "java.util.HashMap";
Class c1 = Class.forName(class1);
Class c2 = Class.forName(class2);
System.out.println(c1.isAssignableFrom(c2)); // true
您可以做的一个选择是使用 Class.forName()
获取 Class 对象,然后使用 obj.getSuperClass()
和 obj.getCanonicalName()
检查继承。以下程序对此进行了演示:
public static void main(String[] args) {
try {
Class str = Class.forName("java.lang.String");
Class ex = Class.forName("java.lang.StringBuilder");
Class superStr = str;
Class superEx = ex;
Boolean strIsSuperEx = false;
Boolean exIsSuperStr = false;
Boolean bothClassesExist = true;
while((!strIsSuperEx && !exIsSuperStr) && bothClassesExist) {
if (superStr != null) {
superStr = superStr.getSuperclass();
}
if (superEx != null) {
superEx = superEx.getSuperclass();
}
bothClassesExist = (superStr != null) && (superEx != null);
if (superStr != null) {
String canonicalName = superStr.getCanonicalName();
String exName = ex.getCanonicalName();
exIsSuperStr = exName.equals(canonicalName);
}
if (superEx != null) {
String canonicalName = superEx.getCanonicalName();
String strName = str.getCanonicalName();
strIsSuperEx = strName.equals(canonicalName);
}
}
if (strIsSuperEx) {
System.out.println(str.getCanonicalName() + " is a superclass of " + ex.getCanonicalName());
} else if (exIsSuperStr) {
System.out.println(ex.getCanonicalName() + " is a superclass of " + str.getCanonicalName());
} else {
System.out.println("Neither class is a superclass of the other.");
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
基于 T.J 的回答。 Crowder,Brian 的评论和 this page 中的代码,我构建了这个答案:
public boolean isSuperclass(final String className1, final String className2)
{
//build a URL Class Loader
final String[] classPathEntries = JavaRuntime.computeDefaultRuntimeClassPath(iJavaProject);
final List<URL> urlList = new ArrayList<URL>();
for (int i = 0; i < classPathEntries.length; i++)
{
final String entry = classPathEntries[i];
final IPath path = new Path(entry);
final URL url = path.toFile().toURI().toURL();
urlList.add(url);
}
final ClassLoader parentClassLoader = iJavaProject.getClass().getClassLoader();
final URL[] urls = urlList.toArray(new URL[urlList.size()]);
final URLClassLoader classLoader = new URLClassLoader(urls, parentClassLoader);
// check if is superclass
final Class<?> class1 = Class.forName(className1, true, classLoader);
final Class<?> class2 = Class.forName(className2, true, classLoader);
return class1.isAssignableFrom(class2);
}
由于您的问题中有 IType
,我假设您使用的是 JDT。在这种情况下,您可以通过创建 ITypeHierarchie
.
来查询 IType
的所有超类型(类 和接口)
唯一需要注意的是java.lang.Object
不会被包含在ITypeHierarchie
中(参见ITypeHierarchy.getAllSupertypes
的Javadoc),所以你需要检查一下单独为此。
if (class1.equals("java.lang.Object")
return true;
ITypeHierarchy typeHierarchy = type.newTypeHierarchy(new NullProgressMonitor());
IType[] supertypes = typeHierarchy.getAllSupertypes(type);
boolean isSuperType = Arrays.asList(supertypes).stream().anyMatch(supertype -> {
return supertype.getFullyQualifiedName().equals(class1);
});
我需要知道一个字符串表示的 class 是否超class(直接或传递)另一个 class 也表示为字符串。例如:
String class1 = "java.lang.Object";
String class2 = "java.lang.Exception";
assertTrue( isSuperclass( class1, class2 ) );
我试图获取第二个 class 的 IType 并检查它的超级class名称。我就是这样尝试的:
/**
* Checks if class1 is directly or transitively superclass of class2.
*/
private boolean isSuperclass(final String class1, final String class2)
{
try
{
String className = class2;
while (className!=null)
{
final IType type = this.javaProject.findType(className);
if (type == null)
{
break;
}
className = type.getSuperclassName();
if (class1.equals(className))
{
return true;
}
}
return false;
}
catch (final JavaModelException e)
{
throw new IllegalStateException(e);
}
}
问题是 getSuperclassName return 只是 class 名称,而不是它的完全限定名称。出于这个原因,我不能在循环中再次调用 javaProject.findType 来检查 class2 的任何传递 superclass 是否等于 class1.
所以如果我调用:
isSuperclass( "java.lang.Throwable", "my.exceptions.Exception" )
它将 return 为假,因为
javaProject.findType("my.exceptions.Exception").getSuperclassName()
return只"ParentException",那么下次调用会是
javaProject.findType("ParentException")
其中 return 是空 IType,因为它不是 class 完全限定名称。这仅发生在正在分析的自己的应用程序中声明的 classes; for API classes getSuperclassName returns 完全限定名称。
我也考虑过通过 ITypeBindings 检查 isSuperclass,但我不知道如何从完全限定名称字符串或 IType 中获取 ITypeBinding。
关于如何检查 class 是否是另一个的超级class 的任何想法?
编辑:基于 Class.forName 的解决方案不适用于我的上下文。
如果你实际上可以加载有问题的类,你可以使用Class#isAssignableFrom
:
Class c1 = Class.forName(class1);
Class c2 = Class.forName(class2);
if (c1.isAssignableFrom(c2)) {
// c1 is a superclass or superinterface of c2
}
来自文档:
public boolean isAssignableFrom(Class<?> cls)
Determines if the class or interface represented by this
Class
object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specifiedClass
parameter. It returnstrue
if so; otherwise it returnsfalse
.
例如:
String class1 = "java.lang.Object";
String class2 = "java.util.HashMap";
Class c1 = Class.forName(class1);
Class c2 = Class.forName(class2);
System.out.println(c1.isAssignableFrom(c2)); // true
您可以做的一个选择是使用 Class.forName()
获取 Class 对象,然后使用 obj.getSuperClass()
和 obj.getCanonicalName()
检查继承。以下程序对此进行了演示:
public static void main(String[] args) {
try {
Class str = Class.forName("java.lang.String");
Class ex = Class.forName("java.lang.StringBuilder");
Class superStr = str;
Class superEx = ex;
Boolean strIsSuperEx = false;
Boolean exIsSuperStr = false;
Boolean bothClassesExist = true;
while((!strIsSuperEx && !exIsSuperStr) && bothClassesExist) {
if (superStr != null) {
superStr = superStr.getSuperclass();
}
if (superEx != null) {
superEx = superEx.getSuperclass();
}
bothClassesExist = (superStr != null) && (superEx != null);
if (superStr != null) {
String canonicalName = superStr.getCanonicalName();
String exName = ex.getCanonicalName();
exIsSuperStr = exName.equals(canonicalName);
}
if (superEx != null) {
String canonicalName = superEx.getCanonicalName();
String strName = str.getCanonicalName();
strIsSuperEx = strName.equals(canonicalName);
}
}
if (strIsSuperEx) {
System.out.println(str.getCanonicalName() + " is a superclass of " + ex.getCanonicalName());
} else if (exIsSuperStr) {
System.out.println(ex.getCanonicalName() + " is a superclass of " + str.getCanonicalName());
} else {
System.out.println("Neither class is a superclass of the other.");
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
基于 T.J 的回答。 Crowder,Brian 的评论和 this page 中的代码,我构建了这个答案:
public boolean isSuperclass(final String className1, final String className2)
{
//build a URL Class Loader
final String[] classPathEntries = JavaRuntime.computeDefaultRuntimeClassPath(iJavaProject);
final List<URL> urlList = new ArrayList<URL>();
for (int i = 0; i < classPathEntries.length; i++)
{
final String entry = classPathEntries[i];
final IPath path = new Path(entry);
final URL url = path.toFile().toURI().toURL();
urlList.add(url);
}
final ClassLoader parentClassLoader = iJavaProject.getClass().getClassLoader();
final URL[] urls = urlList.toArray(new URL[urlList.size()]);
final URLClassLoader classLoader = new URLClassLoader(urls, parentClassLoader);
// check if is superclass
final Class<?> class1 = Class.forName(className1, true, classLoader);
final Class<?> class2 = Class.forName(className2, true, classLoader);
return class1.isAssignableFrom(class2);
}
由于您的问题中有 IType
,我假设您使用的是 JDT。在这种情况下,您可以通过创建 ITypeHierarchie
.
IType
的所有超类型(类 和接口)
唯一需要注意的是java.lang.Object
不会被包含在ITypeHierarchie
中(参见ITypeHierarchy.getAllSupertypes
的Javadoc),所以你需要检查一下单独为此。
if (class1.equals("java.lang.Object")
return true;
ITypeHierarchy typeHierarchy = type.newTypeHierarchy(new NullProgressMonitor());
IType[] supertypes = typeHierarchy.getAllSupertypes(type);
boolean isSuperType = Arrays.asList(supertypes).stream().anyMatch(supertype -> {
return supertype.getFullyQualifiedName().equals(class1);
});