我想创建一个通用的内部类来打开不同类型的流。为此,我做了以下事情:
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));
有出路吗?
答案 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?