我正在尝试实现一个代码分析器,它将另一个Java文件作为输入.对于每个变量声明,我想检查变量所属的类型是否是通用的.有一个简单的方法吗?
例如,我想它:
isGenericType("HashSet") -> true
isGenericType("int") -> false
Run Code Online (Sandbox Code Playgroud)
我可以创建一个包含所有泛型类型的注册表,但问题是如果我实现自定义泛型类型,那么我每次都必须更新注册表.有一些简单的解决方案吗?
即使HashSet可以是通用的,类型HashSet本身(没有<T>)也是原始类型.因此,我会采用扫描声明变量的实际类型的方法,可能在类型上应用正则表达式以查看尖括号是否存在:
isGenericType --> matches the pattern [a-zA-Z_\$][\w\$]*<[a-zA-Z_\$][\w\$]*>
Run Code Online (Sandbox Code Playgroud)
如果要严格考虑有效标识,可以在Java语言规范中检查其定义:
标识符:
IdentifierChars但不是Keyword或BooleanLiteral或NullLiteral
IdentifierChars:
JavaLetter {JavaLetterOrDigit}
JavaLetter:
任何Unicode字符都是"Java字母"
JavaLetterOrDigit:
任何Unicode字符,即"Java字母或数字"
"Java letter"是该方法
Character.isJavaIdentifierStart(int)返回true 的字符."Java letter-or-digit"是该方法
Character.isJavaIdentifierPart(int)返回true 的字符.
我认为这与您所寻找的类似:
它打印true为java.util.HashSet.
但false对java.lang.Object.
public class TestGenerics
{
public static boolean isGenericType(String s) throws ClassNotFoundException
{
Class c = Class.forName(s);
return c.getTypeParameters().length > 0;
}
public static void main(String[] args) throws ClassNotFoundException
{
System.out.println(isGenericType("java.util.HashSet"));
System.out.println(isGenericType("java.lang.Object"));
}
}
Run Code Online (Sandbox Code Playgroud)
这将通过对象,类或类名进行测试.
更新:基于有用的评论对此代码的几个修订提供了一些有趣的测试用例.但是,最终问题的适当解决方案恰恰取决于问题的定义方式.请参阅早期版本和评论.
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
public class GenericTest
{
public static void main(String[] args)
{
try
{
new GenericTest().testAll();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
System.exit(0);
}
public void testAll() throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
Object a = new HashMap<String, Object>();
Object b = new HashMap();
int c = 0;
isGeneric(a);
System.out.println("\n");
isGeneric(b);
System.out.println("\n");
isGeneric(c);
System.out.println("\n");
isGeneric("java.util.HashMap");
System.out.println("\n");
isGeneric("java.lang.Integer");
System.out.println("\n");
isGeneric(new TestA());
System.out.println("\n");
isGeneric(new TestB());
System.out.println("\n");
isGeneric(new TestB<String>());
System.out.println("\n");
isGeneric(new TestC());
System.out.println("\n");
isGeneric(new TestD());
System.out.println("\n");
isGeneric(new TestE());
System.out.println("\n");
return;
}
public static void isGeneric(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
GenericTest.isGeneric(Class.forName(className));
return;
}
public static boolean isGeneric(Object o)
{
return isGeneric(o.getClass());
}
public static boolean isGeneric(Class<?> c)
{
boolean hasTypeParameters = hasTypeParameters(c);
boolean hasGenericSuperclass = hasGenericSuperclass(c);
// boolean hasGenericSuperinterface = hasGenericSuperinterface(c);
// boolean isGeneric = hasTypeParameters || hasGenericSuperclass || hasGenericSuperinterface;
boolean isGeneric = hasTypeParameters || hasGenericSuperclass;
System.out.println(c.getName() + " isGeneric: " + isGeneric);
return isGeneric;
}
public static boolean hasTypeParameters(Class<?> c)
{
boolean flag = c.getTypeParameters().length > 0;
System.out.println(c.getName() + " hasTypeParameters: " + c.getTypeParameters().length);
return flag;
}
public static boolean hasGenericSuperclass(Class<?> c)
{
Class<?> testClass = c;
while (testClass != null)
{
Type t = testClass.getGenericSuperclass();
if (t instanceof ParameterizedType)
{
System.out.println(c.getName() + " hasGenericSuperclass: " + t.getClass().getName());
return true;
}
testClass = testClass.getSuperclass();
}
return false;
}
public static boolean hasGenericSuperinterface(Class<?> c)
{
for (Type t : c.getGenericInterfaces())
{
if (t instanceof ParameterizedType)
{
System.out.println(c.getName() + " hasGenericSuperinterface: " + t.getClass().getName());
return true;
}
}
return false;
}
public interface TestX<X> { }
public interface TestY extends TestX<String> { }
public class TestA implements TestY { }
public class TestB<V> extends TestA { }
public class TestC extends TestB<String> { }
public class TestD extends TestA { }
public class TestE extends TestC { }
}
Run Code Online (Sandbox Code Playgroud)
运行上面代码的结果:
java.util.HashMap hasTypeParameters: 2
java.util.HashMap hasGenericSuperclass: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.util.HashMap isGeneric: true
java.util.HashMap hasTypeParameters: 2
java.util.HashMap hasGenericSuperclass: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.util.HashMap isGeneric: true
java.lang.Integer hasTypeParameters: 0
java.lang.Integer isGeneric: false
java.util.HashMap hasTypeParameters: 2
java.util.HashMap hasGenericSuperclass: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.util.HashMap isGeneric: true
java.lang.Integer hasTypeParameters: 0
java.lang.Integer isGeneric: false
GenericTest$TestA hasTypeParameters: 0
GenericTest$TestA isGeneric: false
GenericTest$TestB hasTypeParameters: 1
GenericTest$TestB isGeneric: true
GenericTest$TestB hasTypeParameters: 1
GenericTest$TestB isGeneric: true
GenericTest$TestC hasTypeParameters: 0
GenericTest$TestC hasGenericSuperclass: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
GenericTest$TestC isGeneric: true
GenericTest$TestD hasTypeParameters: 0
GenericTest$TestD isGeneric: false
GenericTest$TestE hasTypeParameters: 0
GenericTest$TestE hasGenericSuperclass: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
GenericTest$TestE isGeneric: true
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1698 次 |
| 最近记录: |