动态查找表示原始Java类型的类。

时间:2022-02-02 16:27:19

I need to make some reflective method calls in Java. Those calls will include methods that have arguments that are primitive types (int, double, etc.). The way to specify such types when looking up the method reflectively is int.class, double.class, etc.

我需要在Java中进行一些反射的方法调用。这些调用将包括具有基本类型(int, double, etc.)的参数的方法。在用反射方式查找方法时指定此类类型的方法是int.class, double。类等。

The challenge is that I am accepting input from an outside source that will specify the types dynamically. Therefore, I need to come up with these Class references dynamically as well. Imagine a delimited file a list of method names with lists of parameter types:

挑战在于,我接受来自外部源的输入,它将动态地指定类型。因此,我还需要动态地提出这些类引用。想象一个分隔的文件列表,列出了参数类型列表的方法名称:

doSomething int double
doSomethingElse java.lang.String boolean

If the input was something like java.lang.String, I know I could use Class.forName("java.lang.String") to that Class instance back. Is there any way to use that method, or another, to get the primitive type Classes back?

如果输入类似java.lang。String,我知道我可以使用Class. forname(“java.lang.String”)来返回这个类实例。是否有方法可以使用该方法或另一种方法来返回原始类型类?

Edit: Thanks to all the respondents. It seems clear that there is no built-in way to cleanly do what I want, so I will settle for reusing the ClassUtils class from the Spring framework. It seems to contain a replacement for Class.forName() that will work with my requirements.

编辑:感谢所有的回复者。很明显,没有内置的方法可以很好地实现我想要的功能,所以我将满足于从Spring框架中重用ClassUtils类。它似乎包含了一个类. forname()的替换,它将符合我的要求。

7 个解决方案

#1


18  

The Spring framework contains a utility class ClassUtils which contains the static method forName. This method can be used for the exact purpose you described.

Spring框架包含一个实用程序类ClassUtils,其中包含forName的静态方法。此方法可用于您描述的确切用途。

In case you don’t like to have a dependency on Spring: the source code of the method can be found e. g. here on their public repository. The class source code is licensed under the Apache 2.0 model.

如果您不喜欢在Spring上有依赖关系,那么可以找到方法的源代码。在他们的公共存储库中。类源代码是在Apache 2.0模型下授权的。

Note however that the algorithm uses a hard-coded map of primitive types.

注意,该算法使用一种硬编码的原始类型映射。


Edit: Thanks to commenters Dávid Horváth and Patrick for pointing out the broken link.

编辑:感谢David Horvath和Patrick的评论,他们指出了链接的错误。

#2


23  

The Class instances for the primitive types are obtainable as you said using e.g. int.class, but it is also possible to get the same values using something like Integer.TYPE. Each primitive wrapper class contains a static field, TYPE, which has the corresponding primitive class instance.

基本类型的类实例可以像您说的那样使用,例如int.class,但是也可以使用像Integer.TYPE这样的东西获得相同的值。每个原始包装类都包含一个静态字段类型,它具有相应的原始类实例。

You cannot obtain the primitive class via forName, but you can get it from a class which is readily available. If you absolutely must use reflection, you can try something like this:

您不能通过forName获得原始类,但是您可以从一个容易获得的类中获取它。如果你绝对必须使用反射,你可以尝试这样的方法:

Class clazz = Class.forName("java.lang.Integer");
Class intClass = clazz.getField("TYPE").get(null);

intClass.equals(int.class);         // => true

#3


16  

Probably you just need to map the primitives and for the rest of the classes perform the "forName" method:

可能您只需要映射原语和其他类执行“forName”方法:

I would do something like:

我会做一些类似的事情:

void someWhere(){
     String methodDescription = "doSomething int double java.lang.Integer java.lang.String"
     String [] parts = methodDescription.split();
     String methodName= parts[0]
     Class [] paramsTypes = getParamTypes( parts ); // Well, not all the array, but a, sub array from 1 to arr.length..  

    Method m = someObject.class.getMethod( methodName, paramTypes );
    etc. etc etc.
}

public Class[] paramTypes( String [] array ){
     List<Class> list = new ArrayList<Class>();
     for( String type : array ) {
         if( builtInMap.contains( type )) {
             list.add( builtInMap.get( type ) );
          }else{
             list.add( Class.forName( type ) );
          }
     }
     return list.toArray();
}  

    // That's right.
Map<String,Class> builtInMap = new HashMap<String,Class>();{
       builtInMap.put("int", Integer.TYPE );
       builtInMap.put("long", Long.TYPE );
       builtInMap.put("double", Double.TYPE );
       builtInMap.put("float", Float.TYPE );
       builtInMap.put("bool", Boolean.TYPE );
       builtInMap.put("char", Character.TYPE );
       builtInMap.put("byte", Byte.TYPE );
       builtInMap.put("void", Void.TYPE );
       builtInMap.put("short", Short.TYPE );
}

That is, create a map where the primitives types are stored and if the description belong to a primitive then use the mapped class. This map may also be loaded from an external configuration file, to add flexibility so you add String as a built in instead of java.lang.String or potentially have method like this.

也就是说,创建原始类型存储的映射,如果描述属于一个原语,那么使用映射的类。此映射还可以从外部配置文件加载,以增加灵活性,因此您可以将字符串作为内置的而不是java.lang添加。字符串或可能有这样的方法。

"doSomething string yes|no "

“doSomething字符串|否”

There are lots of this kind of code in OS projects like Struts, Hibernate, Spring and Apache libs ( just to mention a few ) , so you don't need to start from zero.

在OS项目中有很多这样的代码,比如Struts、Hibernate、Spring和Apache libs(仅仅提到一些),所以您不需要从零开始。

BTW. I did not compile the above code, but I'm pretty sure it works with little modifications don't down vote me for that.

顺便说一句。我没有编译上面的代码,但是我很确定它的工作原理是没有什么修改的,请不要投我的票。

#4


5  

Apache Commons Lang has ClassUtils.getClass(String), which supports primitive types.

Apache Commons Lang有ClassUtils.getClass(String),它支持基本类型。

#5


3  

A number of Class methods don't handle primitives in a consistent fashion unfortunately. A common way around this in forName is to have a table like;

不幸的是,许多类方法并不以一致的方式处理原语。在forName中常见的一种方法是使用一个表;

private static final Map<String, Class> BUILT_IN_MAP = 
    new ConcurrentHashMap<String, Class>();

static {
    for (Class c : new Class[]{void.class, boolean.class, byte.class, char.class,  
            short.class, int.class, float.class, double.class, long.class})
        BUILT_IN_MAP.put(c.getName(), c);
}

public static Class forName(String name) throws ClassNotFoundException {
    Class c = BUILT_IN_MAP.get(name);
    if (c == null)
        // assumes you have only one class loader!
        BUILT_IN_MAP.put(name, c = Class.forName(name));
    return c;
}

#6


2  

The following code talks about how to get the class of a primitive type who's field name is known, e.g. in this case 'sampleInt'.

下面的代码将讨论如何获取一个名为“sampleInt”的原始类型的字段名。

public class CheckPrimitve {
    public static void main(String[] args) {
        Sample s = new Sample();
        try {
            System.out.println(s.getClass().getField("sampleInt").getType() == int.class); // returns true
            System.out.println(s.getClass().getField("sampleInt").getType().isPrimitive()); // returns true
        } catch (NoSuchFieldException e) {          
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }       
    }
}

class Sample {
    public int sampleInt;
    public Sample() {
        sampleInt = 10;
    }
}

One can also check whether a given value is primitive or not by getting it's respective wrapper class or it's field value.

还可以通过获取相应的包装器类或字段值来检查给定值是否原始。

    public class CheckPrimitve {
        public static void main(String[] args) {
            int i = 3;
            Object o = i;
            System.out.println(o.getClass().getSimpleName().equals("Integer")); // returns true
            Field[] fields = o.getClass().getFields();
            for(Field field:fields) {
                System.out.println(field.getType()); // returns {int, int, class java.lang.Class, int}
            }
        }
    }

#7


0  

Google Guava offers com.google.common.primitives.Primitives for this sort of stuff.

谷歌Guava提供了com. Google .common.原生。这类东西的原语。

#1


18  

The Spring framework contains a utility class ClassUtils which contains the static method forName. This method can be used for the exact purpose you described.

Spring框架包含一个实用程序类ClassUtils,其中包含forName的静态方法。此方法可用于您描述的确切用途。

In case you don’t like to have a dependency on Spring: the source code of the method can be found e. g. here on their public repository. The class source code is licensed under the Apache 2.0 model.

如果您不喜欢在Spring上有依赖关系,那么可以找到方法的源代码。在他们的公共存储库中。类源代码是在Apache 2.0模型下授权的。

Note however that the algorithm uses a hard-coded map of primitive types.

注意,该算法使用一种硬编码的原始类型映射。


Edit: Thanks to commenters Dávid Horváth and Patrick for pointing out the broken link.

编辑:感谢David Horvath和Patrick的评论,他们指出了链接的错误。

#2


23  

The Class instances for the primitive types are obtainable as you said using e.g. int.class, but it is also possible to get the same values using something like Integer.TYPE. Each primitive wrapper class contains a static field, TYPE, which has the corresponding primitive class instance.

基本类型的类实例可以像您说的那样使用,例如int.class,但是也可以使用像Integer.TYPE这样的东西获得相同的值。每个原始包装类都包含一个静态字段类型,它具有相应的原始类实例。

You cannot obtain the primitive class via forName, but you can get it from a class which is readily available. If you absolutely must use reflection, you can try something like this:

您不能通过forName获得原始类,但是您可以从一个容易获得的类中获取它。如果你绝对必须使用反射,你可以尝试这样的方法:

Class clazz = Class.forName("java.lang.Integer");
Class intClass = clazz.getField("TYPE").get(null);

intClass.equals(int.class);         // => true

#3


16  

Probably you just need to map the primitives and for the rest of the classes perform the "forName" method:

可能您只需要映射原语和其他类执行“forName”方法:

I would do something like:

我会做一些类似的事情:

void someWhere(){
     String methodDescription = "doSomething int double java.lang.Integer java.lang.String"
     String [] parts = methodDescription.split();
     String methodName= parts[0]
     Class [] paramsTypes = getParamTypes( parts ); // Well, not all the array, but a, sub array from 1 to arr.length..  

    Method m = someObject.class.getMethod( methodName, paramTypes );
    etc. etc etc.
}

public Class[] paramTypes( String [] array ){
     List<Class> list = new ArrayList<Class>();
     for( String type : array ) {
         if( builtInMap.contains( type )) {
             list.add( builtInMap.get( type ) );
          }else{
             list.add( Class.forName( type ) );
          }
     }
     return list.toArray();
}  

    // That's right.
Map<String,Class> builtInMap = new HashMap<String,Class>();{
       builtInMap.put("int", Integer.TYPE );
       builtInMap.put("long", Long.TYPE );
       builtInMap.put("double", Double.TYPE );
       builtInMap.put("float", Float.TYPE );
       builtInMap.put("bool", Boolean.TYPE );
       builtInMap.put("char", Character.TYPE );
       builtInMap.put("byte", Byte.TYPE );
       builtInMap.put("void", Void.TYPE );
       builtInMap.put("short", Short.TYPE );
}

That is, create a map where the primitives types are stored and if the description belong to a primitive then use the mapped class. This map may also be loaded from an external configuration file, to add flexibility so you add String as a built in instead of java.lang.String or potentially have method like this.

也就是说,创建原始类型存储的映射,如果描述属于一个原语,那么使用映射的类。此映射还可以从外部配置文件加载,以增加灵活性,因此您可以将字符串作为内置的而不是java.lang添加。字符串或可能有这样的方法。

"doSomething string yes|no "

“doSomething字符串|否”

There are lots of this kind of code in OS projects like Struts, Hibernate, Spring and Apache libs ( just to mention a few ) , so you don't need to start from zero.

在OS项目中有很多这样的代码,比如Struts、Hibernate、Spring和Apache libs(仅仅提到一些),所以您不需要从零开始。

BTW. I did not compile the above code, but I'm pretty sure it works with little modifications don't down vote me for that.

顺便说一句。我没有编译上面的代码,但是我很确定它的工作原理是没有什么修改的,请不要投我的票。

#4


5  

Apache Commons Lang has ClassUtils.getClass(String), which supports primitive types.

Apache Commons Lang有ClassUtils.getClass(String),它支持基本类型。

#5


3  

A number of Class methods don't handle primitives in a consistent fashion unfortunately. A common way around this in forName is to have a table like;

不幸的是,许多类方法并不以一致的方式处理原语。在forName中常见的一种方法是使用一个表;

private static final Map<String, Class> BUILT_IN_MAP = 
    new ConcurrentHashMap<String, Class>();

static {
    for (Class c : new Class[]{void.class, boolean.class, byte.class, char.class,  
            short.class, int.class, float.class, double.class, long.class})
        BUILT_IN_MAP.put(c.getName(), c);
}

public static Class forName(String name) throws ClassNotFoundException {
    Class c = BUILT_IN_MAP.get(name);
    if (c == null)
        // assumes you have only one class loader!
        BUILT_IN_MAP.put(name, c = Class.forName(name));
    return c;
}

#6


2  

The following code talks about how to get the class of a primitive type who's field name is known, e.g. in this case 'sampleInt'.

下面的代码将讨论如何获取一个名为“sampleInt”的原始类型的字段名。

public class CheckPrimitve {
    public static void main(String[] args) {
        Sample s = new Sample();
        try {
            System.out.println(s.getClass().getField("sampleInt").getType() == int.class); // returns true
            System.out.println(s.getClass().getField("sampleInt").getType().isPrimitive()); // returns true
        } catch (NoSuchFieldException e) {          
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }       
    }
}

class Sample {
    public int sampleInt;
    public Sample() {
        sampleInt = 10;
    }
}

One can also check whether a given value is primitive or not by getting it's respective wrapper class or it's field value.

还可以通过获取相应的包装器类或字段值来检查给定值是否原始。

    public class CheckPrimitve {
        public static void main(String[] args) {
            int i = 3;
            Object o = i;
            System.out.println(o.getClass().getSimpleName().equals("Integer")); // returns true
            Field[] fields = o.getClass().getFields();
            for(Field field:fields) {
                System.out.println(field.getType()); // returns {int, int, class java.lang.Class, int}
            }
        }
    }

#7


0  

Google Guava offers com.google.common.primitives.Primitives for this sort of stuff.

谷歌Guava提供了com. Google .common.原生。这类东西的原语。