用于打开流的通用内部类

时间:2015-12-07 19:29:48

标签: java generics

我想创建一个通用的内部类来打开不同类型的流。为此,我做了以下事情:

private class StreamOpener<T1, T2>
{
    StreamOpener(String fileName, T1 v1)
    {
        v1 = null;

        try
        {
            v1 = new T1(new T2(fileName));
        }
        catch (FileNotFoundException e)
        {
            System.err.println("File " + fileName + " not found.  Exiting");
            System.exit(-1);
        }
        catch (Exception e)
        {
            System.err.println("Error on file " + fileName + "  Exiting");
            System.exit(-1);
        }
    }
}   

这个想法是,例如,对于读取文本文件,T1可以是Scanner,T2可以是FileInputStream。同样地,对于编写文本文件,T1可以是PrintWriter,T2可以是FileOutputStream。

但是,我在以下行收到编译错误:                 v1 =新T1(新T2(fileName));

有出路吗?

1 个答案:

答案 0 :(得分:1)

您无法完全按照自己发布的内容执行操作,因为Java泛型不是reified。但是,您可以使用type tokens修改示例,尽管这很难看。例如:

private class StreamOpener<T1, T2>
{
    T1 v1;

    StreamOpener(String fileName, Class<T1> t1Class, Class<T2> t2Class)
    {
        try
        {
            Constructor<T2> t2Constructor = t2Class.getConstructor(String.class);
            T2 v2 = t2Constructor.newInstance(fileName);
            Constructor<T1> t1Constructor = t1Class.getConstructor(t2Class);
            v1 = constructor.newInstance(v2);
        }
        catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException|InvocationTargetException e) // yuck
        {
           System.err.println("Reflection error, fire your programmer");
           System.exit(-1);
        }
        catch (FileNotFoundException e)
        {
            System.err.println("File " + fileName + " not found.  Exiting");
            System.exit(-1);
        }
        catch (Exception e)
        {
            System.err.println("Error on file " + fileName + "  Exiting");
            System.exit(-1);
        }
    }
}   

但是,上面的代码非常糟糕。相反,您可以将T1的创建委托给某个界面,如下所示:

interface StreamCreator<T> {
    T open() throws Exception; // code smell
}

然后,您可以在需要对象时调用它。一个实现可能return new Scanner(new InputStream(fileName))。另一个实现可以return new PrintWriter(new FileOutputStream(fileName))。由于它是一个功能接口,您可以在Java 8中使用lambdas定义内联实现。

另一方面,我正在努力弄清楚你为什么要这样做。 Scanner和PrintWriter暴露了两个完全不同的接口。那么,如何以不同的方式创建一个可以创建它们的单个函数呢?调用代码必须特定于Scanner或PrintWriter,那么为什么不使用两种不同的方法创建Scanner或PrintWriter?