简体   繁体   English

如何使用泛型实例化Java中的类实例?

[英]How can I instantiate a class instance in java with generics?

How can I instantiate a class instance in java with generics? 如何使用泛型实例化Java中的类实例?

I am trying to read data from XML file and then instantiate an object so that I can add the other properties of the object (read from the XML file) into the object. 我试图从XML文件读取数据,然后实例化对象,以便可以将对象的其他属性(从XML文件读取)添加到对象中。 I thought the easiest way (so that I don't have to read the class method names and find the setters) would be to instantiate the object with all the values in the constructor. 我认为最简单的方法(这样我就不必读取类方法的名称并查找设置方法)将是使用构造函数中的所有值实例化该对象。

I'm trying to do something like this so I need to have something like: T obj = new Object() but get the objects class 我试图做这样的事情,所以我需要有这样的事情: T obj = new Object()但要获取对象类

    private static final boolean string_field = true;

    private static <T> T getObject(Element e, String[] fieldNames, boolean[] fieldTypes) {
        Object[] values = new Object[fieldNames.length];
        for (int i=0; i<fieldNames.length; i++) {
            values[i] = (fieldTypes[i]==string_field)? getStringValue(e, fieldNames[i])
                    : getIntegerValue(e, fieldNames[i]);
        }
        return new T(values);
    }

Thanks for your advice. 谢谢你的建议。

EDIT: 编辑:

This is my updated code (untested): 这是我更新的代码(未经测试):

    public static <T> List<T> populateObjectList(Document xmlDoc, String tagName,
            Class clazz, String[] fieldNames, Class[] fieldTypes) {
        List<T> objList = new ArrayList<T>();
        NodeList nl = xmlDoc.getElementsByTagName(tagName);
        if (nl!=null && nl.getLength()>0) {
            for (int i=0; i<nl.getLength(); i++) {
                Element e = (Element) nl.item(i);
                T t;
                try {
                    t = getObject(e, clazz, fieldNames, fieldTypes);
                    objList.add(t);
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (IllegalArgumentException ex) {
                } catch (InvocationTargetException ex) {
                } catch (NoSuchMethodException ex) {
                }
            }
        }
        return objList;
    }

    private static <T> T getObject(Element e, Class clazz, String[] fieldNames, Class[] fieldTypes)
            throws InstantiationException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, NoSuchMethodException {
        Object[] initargs = new Object[fieldNames.length];
        for (int i=0; i<fieldNames.length; i++) {
            initargs[i] = (fieldTypes[i].getName().equals("int"))?
                getIntegerValue(e, fieldNames[i])
                : getStringValue(e, fieldNames[i]);
        }
        return (T) clazz.getConstructor(fieldTypes).newInstance(initargs);
    }

I posted this so that some of you would understand what I'm trying to do. 我发布了这个信息,以便你们中的一些人了解我正在尝试做的事情。

Thanks again everyone for their advice. 再次感谢大家的建议。

You cannot instantiate a generic type. 您不能实例化泛型类型。 Java generics have an annoying feature called type erasure , which basically means that the JVM doesn't know what type was used for a generic class or method at runtime. Java泛型具有一个令人讨厌的特性,称为类型擦除 ,它基本上意味着JVM在运行时不知道泛型类或方法使用了哪种类型。 This is for backwards compatibility with pre-generic versions of generic classes, such as collections. 这是为了向后兼容通用类的通用版本,例如集合。

What you can do is add a Class<T> clazz to your parameter list, then replace the end of the method with this: 您可以做的是将Class<T> clazz添加到参数列表,然后用以下方法替换方法的结尾:

Class<?>[] paramTypes = new Class[values.length];
for (int i = 0; i < paramTypes.length; i++) {
    paramTypes[i] = values[i].getClass();
}
return clazz.getConstructor(paramTypes).newInstance(values);

This will throw an exception if the class doesn't have a constructor that takes the correct type and number of arguments in the correct order. 如果该类没有构造器以正确的顺序采用正确的类型和数量的参数,则将引发异常。

CAVEAT: This only works if the constructor's parameter types are exactly the same as the object types. CAVEAT:仅当构造函数的参数类型与对象类型完全相同时 ,此方法才有效。 For instance, if values consists of { "Hello", new Integer(2) } , then this will only find a constructor with signature SomeClass(String, Integer) , not one with signature SomeClass(Object, Object) . 例如,如果values包含{ "Hello", new Integer(2) } ,那么它将仅找到带有签名SomeClass(String, Integer)的构造函数,而不是带有签名SomeClass(Object, Object)的构造函数。

How would you even know that T contained a constructor that took a single Object[] argument? 您甚至怎么知道T包含一个采用单个Object[]参数的构造函数? The way to fix this is to pass in an abstract factory. 解决此问题的方法是传入一个抽象工厂。

interface ThingFactory { // Choose an appropriate name.
    T create(Object[] values);
}

private static <T> T getObject(
    ThingFactory<T> factory, Element e, String[] fieldNames, boolean[] fieldTypes
) { 
    ...
    return factory.create(values);
}

Now T might not even have a rather strange Object[] constructor. 现在, T甚至可能没有一个很奇怪的Object[]构造函数。 T might be an abstract type. T可能是抽象类型。 The factory might return a different type dependent upon the arguments. 工厂可能会根据参数返回不同的类型。 Perhaps sometimes these products are immutable objects that can be cached. 也许有时这些产品是可以缓存的不可变对象。

You can't do new T() because at runtime, T is effectively just Object . 您不能执行new T()因为在运行时, T实际上只是Object The compiler uses generics for type-checking (eg you can't put an Integer into a List<String> ), but then throws the generics information away. 编译器使用泛型进行类型检查(例如,您不能将Integer放入List<String> ),但随后会将泛型信息丢弃。 There's one compiled copy of the method for all types of arguments, so there's no way for it to know which type you expect it to instantiate. 该方法针对所有类型的参数都有一个已编译的副本,因此它无法知道您希望实例化哪种类型。

Read about type erasure for more information. 阅读有关类型擦除的更多信息。

我真的看不到您的问题,无法使用obj.getClass吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM