有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

反射如何检查类是否属于JavaJDK

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

List<?> list = externalLibrary.search(...);
for(clazz : list) {
    if (clazz.getPackage().getName().startsWith("java.lang"))
      // do something different
}

有更好的吗


共 (6) 个答案

  1. # 1 楼答案

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

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

    if (theObject.getClass().getClassLoader() == "".getClass().getClassLoader()) ...
    

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

  2. # 2 楼答案

    我认为一个更简单的解决办法是这样: 编写一个方法来标识您定义的所有类。在大多数情况下,所有用户定义的类都遵循com这样的模式。某物某物如果它们不属于com。某物这是一个JDK类

  3. # 3 楼答案

    您可以使用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);
      }
        ....
      }
    
  4. # 4 楼答案

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

    public class JDKClass {
    
        private static Set<String> CS = new HashSet<String>();
    
        static {
            try {
                File file = new File(System.getProperty("java.home"),
                        "lib/classlist");
                BufferedReader r = new BufferedReader(new FileReader(file));
                String l;
                while (true) {
                    l = r.readLine();
                    if (l == null) {
                        break;
                    } else {
                        CS.add(l.replace('/', '.'));
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public static boolean contains(String o) {
            return CS.contains(o) || o.startsWith("java") || o.startsWith("com.sun")
                    || o.startsWith("sun") || o.startsWith("oracle")
                    || o.startsWith("org.xml") || o.startsWith("com.oracle");
        }
    
        private JDKClass() {
        }
    
    }
    
  5. # 5 楼答案

    就我个人而言,我喜欢类加载器基本答案。但在StringBuilder上,它也将返回真值。如果您想要更窄的定义,即仅为“内置”类型,那么可以尝试评估这是基元类型(如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;
         }
    
        } 
    

    您还可以选择添加对java.math.BigDecimaljava.util.Datejava.sql.Timestamp等类的支持。但是请注意,它们不是最终的,所以我假设如果有人以琐碎的方式扩展它们,它将不会被视为JDK类

  6. # 6 楼答案

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

    java
    javax
    com.sun
    sun
    

    也许其他人