我有一节课看起来像这样。。。
public class LegionInputFormat
extends FileInputFormat<NullWritable, LegionRecord> {
@Override
public RecordReader<NullWritable, LegionRecord>
createRecordReader(InputSplit split, TaskAttemptContext context) {
/* Skipped code for getting recordDelimiterBytes */
return new LegionRecordReader(recordDelimiterBytes);
}
}
我想使用泛型类型,以便它可以返回用户指定的任何类型的recordreader,如下所示:
public class LegionInputFormat<T extends RecordReader<NullWritable, LegionRecord>>
extends FileInputFormat<NullWritable, LegionRecord> {
@Override
public RecordReader<NullWritable, LegionRecord>
createRecordReader(InputSplit split, TaskAttemptContext context) {
/* Skipped code for getting recordDelimiterBytes */
return new T(recordDelimiterBytes);
}
}
正如文章标题所示,我被告知“无法示例化t类型”。从其他堆栈交换文章中,我发现这是不可能的,因为泛型是如何工作的。我没能收集到的是为什么会这样的直观解释。我通过理解才能学得最好,所以如果有人能提供帮助,那将是非常有帮助的。
我还对实现我在这里要做的事情的最佳实践感兴趣。构造器应该 LegionInputFormat
接受 RecordReader
类,存储它,然后稍后引用它以创建新示例?还是有更好的解决办法?
(其他背景-这里的上下文是hadoop,但我怀疑它是否重要。我是一个相当有成就的数据科学家,但我对java还很陌生。)
2条答案
按热度按时间slwdgvem1#
在第二个代码示例中,编译器无法知道
T
有一个接受recordDelimiterBytes
作为论据。这是因为每个类都是一个独立的编译单元LegionInputFormat
是编译的,编译器只知道T
是一个RecordReader<NullWritable, LegionRecord>
. 它不知道哪种混凝土是用来T
,它必须假设以后有人可以加入任何扩展的类RecordReader<NullWritable, LegionRecord>
. 我们可以告诉编译器T
使用extends
,但在java中,我们无法指定T
有一个构造函数T(byte[])
(或任何类型的recordDelimiterBytes
是)。我已经多次使用下面的解决方案,尽管它需要创建子类,但我对它非常满意。这项工作仍在泛型类中。现宣布为摘要:
对于示例化,它需要您编写一个具体的子类,其中只有以下几行:
在子类中,我们知道
T
因此类的构造函数,所以我们可以示例化它。虽然没有你所希望的那么简单,但我认为这个解决方案很好,很干净。在我自己的代码中,我利用这个机会将工厂方法声明为返回类型
T
:然后您只需在实施过程中跟进:
在这种情况下,它甚至会缩短几个字符。另一方面,在你的情况下,你似乎不需要它,所以你可能更喜欢留在较弱的回报类型
RecordReader<NullWritable, LegionRecord>
.llycmphe2#
正如文章标题所示,我被告知“无法示例化t类型”。从其他堆栈交换文章中,我发现这是不可能的,因为泛型是如何工作的。
这是因为java中的泛型纯粹是编译时特性;编译器丢弃泛型(这称为“类型擦除”),这样在运行时就没有类型变量了
T
,所以你不能这样做new T(...)
.在java中,可以通过传递
Class<T>
对象创建的示例的方法T
,然后通过反射创建示例。