Reflection 如何检查类是否属于JavaJDK

Reflection 如何检查类是否属于JavaJDK,reflection,java,Reflection,Java,我使用一个外部库,它返回一些列表。 我需要检查这个列表中的每个对象是否都是JDK的对象(String、int、Integer…)。 这是正确的解决方案吗 List<?> list = externalLibrary.search(...); for(clazz : list) { if (clazz.getPackage().getName().startsWith("java.lang")) // do something different } List L

我使用一个外部库,它返回一些
列表
。 我需要检查这个列表中的每个对象是否都是JDK的对象(String、int、Integer…)。 这是正确的解决方案吗

List<?> list = externalLibrary.search(...);
for(clazz : list) {
    if (clazz.getPackage().getName().startsWith("java.lang"))
      // do something different
}
List List=externalLibrary.search(…);
对于(clazz:list){
if(clazz.getPackage().getName().startsWith(“java.lang”))
//做些不同的事情
}

有更好的吗?

这取决于你对“JDK对象”的定义——它的边缘可能会变得非常模糊——不,这不可能做到。
java.lang
包只是JDK中所有类的一小部分

您可以检查每个对象是否由加载的
java.lang.String
相同的
ClassLoader
加载,即


一般来说,系统类和应用程序类将使用不同的
类加载器

可能没问题,只需检查以下软件包:

java
javax
com.sun
sun

可能其他人…

我个人喜欢类加载器的基本答案。但在StringBuilder上也会返回true。如果您想要更窄的定义,即仅为“内置”类型,则可以尝试评估这是基元类型(如int)还是包装类型(如Integer)或字符串。你可以这样写:

    import java.util.Map;
    import java.util.TreeMap;



    public class Utils {

        private static Map<String, Class<?>> SUBST_MAP = new TreeMap<String, Class<?>>();
        private static Map<String, Class<?>> SIMPLE_MAP = new TreeMap<String, Class<?>>();


        static {
            SUBST_MAP.put(Byte.class.getName(), Byte.TYPE);
            SUBST_MAP.put(Short.class.getName(), Short.TYPE);
            SUBST_MAP.put(Integer.class.getName(), Integer.TYPE);
            SUBST_MAP.put(Long.class.getName(), Long.TYPE);
            SUBST_MAP.put(Float.class.getName(), Float.TYPE);
            SUBST_MAP.put(Double.class.getName(), Double.TYPE);
            SUBST_MAP.put(Boolean.class.getName(), Boolean.TYPE);
            SUBST_MAP.put(Character.class.getName(), Character.TYPE);
            SIMPLE_MAP.put(String.class.getName(), Boolean.TRUE);

        }




    /**
     * Gets the the class type of the types of the argument.
     * 
     * if substPrimitiveWrapper is true,
     * then if there is argument, that represent primitive type wrapper (such as Integer),
     *      then it will be substituted to primitive type (such as int).
     * else no substitution will be done.
     *
     * @param arg object.
     * @param substPrimitiveWrapper - wheteher to do primitive type substitution.
     * @retrun class type.
     */

    public static Class<?> getClassType(Object arg, boolean substPrimitiveWrapper){
        Class<?> classType = null;
        String className = null;
        Class<?> substClass = null;

        if(arg != null ){
            //making default classType
            classType = arg.getClass();
            if(substPrimitiveWrapper){
                className = classType.getName();
                substClass = (Class<?>)SUBST_MAP.get(className);
                if(substClass != null){
                    classType = substClass;
                }

            }
        }
        return classType;
    }

    /**
     * This method consider JDK type any primitive type, wrapper class or String.
     * 
     * 
     * @param arg object
     * @return where arg is JDK type or now.
     */
    public static boolean isJDKClass(Object arg){
        Class<?> classType = getClassType(arg, true);
        boolean isJDKClass = false;
        if(classType!=null){
            //if(String.class.equals(classType)){
            //  isJDKClass = true; //this is String, note that String is final
            //}
            assert classType!=null;
            String className = classType.getName();
            Boolean isFound = (Boolean)SIMPLE_MAP.get(className);
            if(Boolean.TRUE.equals(isFound)){
                isJDKClass = true; //this is predefined class
            }


            boolean isPrimitiveType = classType.isPrimitive();
            if(isPrimitiveType){
                isJDKClass = true; //this is primitive type or wrapper class
            }
        }

        return isJDKClass;
     }

    } 
import java.util.Map;
导入java.util.TreeMap;
公共类UTIL{
私有静态映射>();
私有静态映射>();
静止的{
SUBST_MAP.put(Byte.class.getName(),Byte.TYPE);
SUBST_MAP.put(Short.class.getName(),Short.TYPE);
SUBST_MAP.put(Integer.class.getName(),Integer.TYPE);
SUBST_MAP.put(Long.class.getName(),Long.TYPE);
SUBST_MAP.put(Float.class.getName(),Float.TYPE);
SUBST_MAP.put(Double.class.getName(),Double.TYPE);
SUBST_MAP.put(Boolean.class.getName(),Boolean.TYPE);
SUBST_MAP.put(Character.class.getName(),Character.TYPE);
SIMPLE_MAP.put(String.class.getName(),Boolean.TRUE);
}
/**
*获取参数类型的类类型。
* 
*如果SubPrimitiveWrapper为true,
*然后,如果存在表示基元类型包装器(如Integer)的参数,
*然后它将被替换为基元类型(如int)。
*否则将不进行替换。
*
*@param arg对象。
*@param subprimitivewrapper-是否执行原语类型替换。
*@retrun类类型。
*/
公共静态类getClassType(对象参数,布尔子基元包装器){
类类型=空;
字符串className=null;
类subclass=null;
如果(arg!=null){
//创建默认类类型
classType=arg.getClass();
if(subprimitivewrapper){
className=classType.getName();
subclass=(Class)SUBST_MAP.get(className);
if(子类!=null){
classType=子类;
}
}
}
返回类类型;
}
/**
*该方法考虑JDK类型的任何基元类型、包装类或字符串。
* 
* 
*@param arg对象
*@return其中arg是JDK类型或now。
*/
公共静态布尔isJDKClass(对象arg){
Class classType=getClassType(arg,true);
布尔值isJDKClass=false;
if(类类型!=null){
//if(String.class.equals(classType)){
//isJDKClass=true;//这是字符串,请注意字符串是最终的
//}
断言类类型!=null;
字符串className=classType.getName();
Boolean isFound=(Boolean)SIMPLE_MAP.get(className);
if(Boolean.TRUE.equals(isFound)){
isJDKClass=true;//这是预定义的类
}
布尔isPrimitiveType=classType.isPrimitive();
if(isPrimitiveType){
isJDKClass=true;//这是基元类型或包装类
}
}
返回isJDKClass;
}
} 

您还可以选择添加对此类类的支持,如
java.math.BigDecimal
java.util.Date
java.sql.Timestamp
。但是请注意,它们不是最终的,所以我假设如果有人以一种微不足道的方式扩展它们,它也不会被视为JDK类。

我们使用下面的类来检查这些类是否属于JDK

公共类JDKClass{
私有静态集CS=newhashset();
静止的{
试一试{
File File=新文件(System.getProperty(“java.home”),
“lib/classlist”);
BufferedReader r=新的BufferedReader(新文件读取器(文件));
字符串l;
while(true){
l=r.readLine();
if(l==null){
打破
}否则{
CS.添加(l.替换(“/”,“.”);
}
}
}捕获(例外e){
抛出新的运行时异常(e);
}
}
公共静态布尔包含(字符串o){
返回CS.contains(o)| | o.startsWith(“java”)| | o.startsWith(“com.sun”)
||o.startsWith(“太阳”)o.startsWith(“甲骨文”)
||o.startsWith(“org.xml”)| o.startsWith(“com.oracle”);
}
私有JDKClass(){
}
}

您可以使用
ClassLoader.getSystemResources
然后检查类是从哪个jar加载的(例如,如果它来自rt.jar)

您将获得URL,例如:

jar:file:/C:/Users/user/.m2/repository/org/slf4j/slf4j-log4j12/1.6.1/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class
示例代码取自SLF4j:

  private static String STATIC_LOGGER_BINDER_PATH = 
     "org/slf4j/impl/StaticLoggerBinder.class";
  private static void singleImplementationSanityCheck() {
    try {
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class
          .getClassLoader();
      Enumeration paths;
      if (loggerFactoryClassLoader == null) {
        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
      } else {
        paths = loggerFactoryClassLoader
            .getResources(STATIC_LOGGER_BINDER_PATH);
      }
  List implementationList = new ArrayList();
  while (paths.hasMoreElements()) {
    URL path = (URL) paths.nextElement();
    implementationList.add(path);
  }
    ....
  }

我认为一个更简单的解决办法是这样: 编写一个方法来标识您定义的所有类。在大多数情况下,所有用户定义的类都遵循类似com.something.something的模式。如果它们不属于com.something.something,那么它就是一个JDK类
  private static String STATIC_LOGGER_BINDER_PATH = 
     "org/slf4j/impl/StaticLoggerBinder.class";
  private static void singleImplementationSanityCheck() {
    try {
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class
          .getClassLoader();
      Enumeration paths;
      if (loggerFactoryClassLoader == null) {
        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
      } else {
        paths = loggerFactoryClassLoader
            .getResources(STATIC_LOGGER_BINDER_PATH);
      }
  List implementationList = new ArrayList();
  while (paths.hasMoreElements()) {
    URL path = (URL) paths.nextElement();
    implementationList.add(path);
  }
    ....
  }