繁体   English   中英

使用字符串类名实例化泛型变量

[英]Instantiate a generic variable using string class name

我正在使用谷歌的CSVReader,它需要一个类名来创建一个解析器。 使用解析器,我正在将CSV文件读入列表。

考虑以下代码:

ValueProcessorProvider provider = new ValueProcessorProvider();
    CSVEntryParser<A> entryParser = new AnnotationEntryParser<A>(A.class, provider);

    CSVReader<A> newExternalFileCSVReader = 
            new CSVReaderBuilder<A>(m_NewExternalFile).entryParser((CSVEntryParser<A>) entryParser).strategy(new CSVStrategy(',', '"', '#', true, true)).build();
    List<A> m_NewExternalFileData = newExternalFileCSVReader.readAll();

使用此代码,我可以读取特定于A类的CSV文件。
我还有其他几个类:B,C,D,它们都使用上面相同的代码,只是它们各自的类。

可以有一个函数,我将类名称作为String传递,它可以根据String输入名称实例化CSVReader /解析器吗? 而不是必须创建3个不同的代码段(对于类B,C,D),我可以使用相同的一个,只需输入相关的类名?

您可以使用工厂模式。

创建一个接口并在A,B,C和D的基本方法内定义。

然后所有A,B,C和D类都必须实现该接口。

public interface BaseInterface {
    // your methods
}

然后创建一个Factory类,在该类中传递一个标识符,它将使您的阅读器正确启动

package a;

public final class Factory {

    // Not instantiable
    private Factory() {
        throw new AssertionError("Not instantiable");
    }

    public static CSVReader<your interface> getReader(String reader) {

        if ("A".equals(reader)) {
            return new CSVReader<A>();
        } else if ("B".equals(reader)) {
            return new CSVReader<B>();
        }
        // TODO create all your readers
    }
}

现在,您可以通过您的工厂类呼叫读者,如下所示:

ValueProcessorProvider provider = new ValueProcessorProvider();
    CSVEntryParser<A> entryParser = new AnnotationEntryParser<A>(A.class, provider);

    CSVReader<your interface> newExternalFileCSVReader = 
            Factory("your reader type");
    List<your interface> m_NewExternalFileData = newExternalFileCSVReader.readAll();

由于你没有发布A,B,C和D类,你必须自定义该代码,但按照这种方式,我认为你可以完成你想要的。

你可以这样做:

public class MyCSVReader<T> {

    private Class<T> clazz;

    public MyCSVReader(Class<T> clazz) {
        this.clazz = clazz;
    }

    public List<T> readData(File file) {
        ValueProcessorProvider provider = new ValueProcessorProvider();
        CSVEntryParser<T> parser = new AnnotationEntryParser<T>(clazz, provider);
        CSVStrategy strategy = new CSVStrategy(',', '"', '#', true, true);
        CSVReaderBuilder builder = new CSVReaderBuilder<T>(file);
        CSVReader<T> reader = builder.entryParser(parser ).strategy(strategy).build();
        return reader.readAll();
    }
}

然后你会做:

MyCSVReader<A> readerA = new MyCSVReader<>(A.class);
List<A> data = readerA.readData(m_NewExternalFile);

对于任何其他课程也一样。

编辑:也许通过文件扩展名查找类型会有用吗?

public class MyCSVReaderFactory {

    private static Map<String, MyCSVReader<?>> readersByFileExtension = new HashMap<>();

    // files with data for class A have extension .xta, etc.
    static {
        readersByFileExtension.put(".xta", new MyCSVReader<>(A.class));
        readersByFileExtension.put(".xtb", new MyCSVReader<>(B.class));
    }

    public MyCSVReader<?> create(String fileExtension) {
        MyCSVReader<?> reader = readersByFileExtension.get(fileExtension);
        if (reader == null) {
            throw new IllegalArgumentException("Unknown extension: " + fileExtension);
        }
        return reader;
     }
}

public List<?> doStuff(File file) {
    String fileExtension = getFileExtension(file);
    MyCSVReader<?> reader = MyCSVReaderFactory.create(fileExtension);
    return reader.readAll();
}

private String getFileExtension(File file) { 
    // TODO: implement this
}

如果您不需要List(对象),则AD类应实现公共接口或扩展可用于概括的公共超类。

暂无
暂无

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

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