Java 无法实例化类型T
我有一门课看起来像这样Java 无法实例化类型T,java,hadoop,generics,Java,Hadoop,Generics,我有一门课看起来像这样 public class LegionInputFormat extends FileInputFormat<NullWritable, LegionRecord> { @Override public RecordReader<NullWritable, LegionRecord> createRecordReader(InputSplit split, TaskAttemptContex
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);
}
}
公共类LegionInputFormat
扩展FileInputFormat{
@凌驾
公共记录阅读器
createRecordReader(InputSplit拆分,TaskAttemptContext上下文){
/*已跳过获取recordDelimiterBytes的代码*/
返回新的军团记录阅读器(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);
}
}
公共类LegionInputFormat
扩展FileInputFormat{
@凌驾
公共记录阅读器
createRecordReader(InputSplit拆分,TaskAttemptContext上下文){
/*已跳过获取recordDelimiterBytes的代码*/
返回新的T(recordDelimiterBytes);
}
}
正如文章标题所暗示的,从其他堆栈交换文章中,我被告知我“无法实例化类型T”。我收集到这是不可能的,因为泛型是如何工作的。我无法收集到的是关于为什么会这样的直观解释。我通过理解学习得最好,所以如果有人能提供,这将非常有帮助
我还对实现我希望在这里做的事情的最佳实践感兴趣。LegionInputFormat
的构造函数是否应该接受RecordReader
类,存储该类,然后稍后引用它以创建新实例?还是有更好的解决方案
(另外的背景——这里的背景是Hadoop,但我怀疑它是否重要。我是一位相当有成就的数据科学家,但我对Java非常陌生。)
正如文章标题所暗示的,从其他堆栈交换文章中,我被告知我“无法实例化类型T”。我收集到这是不可能的,因为泛型是如何工作的
这是因为Java中的泛型纯粹是编译时特性;编译器丢弃了泛型(称为“”),因此在运行时,没有类型变量T
,因此不能执行newt(…)
在Java中,可以通过将类
对象传递给需要创建T
实例的方法,然后通过创建实例来实现这一点
正如文章标题所暗示的,从其他堆栈交换文章中,我被告知我“无法实例化类型T”。我收集到这是不可能的,因为泛型是如何工作的
这是因为Java中的泛型纯粹是编译时特性;编译器丢弃了泛型(称为“”),因此在运行时,没有类型变量T
,因此不能执行newt(…)
在Java中,可以通过将
类
对象传递给需要创建T
实例的方法,然后通过创建实例来实现这一点。在第二个代码示例中,编译器无法知道T
是否有接受recordDelimiterBytes
作为参数的构造函数。这是因为每个类都是一个独立的编译单元,所以当编译LegionInputFormat
时,编译器只知道T
是一个RecordReader
。它不知道哪些具体类型用于t
,它必须假设以后有人可以加入任何扩展RecordReader
的类。我们可以使用extends
告诉编译器一些关于T
的信息,但是在Java中,我们无法指定T
有一个构造函数T(byte[])
(或者无论recordDelimiterBytes
的类型是什么)
我已经多次使用下面的解决方案,尽管它需要创建子类,但我对它非常满意。这项工作仍在泛型类中。现在宣布为抽象:
public abstract class InputFormat<T extends RecordReader<NullWritable, LegionRecord>>
extends FileInputFormat<NullWritable, LegionRecord> {
private byte[] recordDelimiterBytes;
@Override
public RecordReader<NullWritable, LegionRecord> createRecordReader(InputSplit split, TaskAttemptContext context) {
/* Skipped code for getting recordDelimiterBytes */
return constructRecordReader(recordDelimiterBytes);
}
// factory method for T objects
protected abstract RecordReader<NullWritable, LegionRecord> constructRecordReader(byte[] recordDelimiterBytes);
}
然后,您只需在实施过程中跟进:
protected LegionRecordReader constructRecordReader(byte[] recordDelimiterBytes) {
在这种情况下,它甚至会缩短几个字符。另一方面,在您的例子中,您似乎不需要它,因此您可能更喜欢使用较弱的返回类型
RecordReader
,在第二个代码示例中,编译器无法知道t
是否有接受recordDelimiterBytes
作为参数的构造函数。这是因为每个类都是一个独立的编译单元,所以当编译LegionInputFormat
时,编译器只知道T
是一个RecordReader
。它不知道哪些具体类型用于t
,它必须假设以后有人可以加入任何扩展RecordReader
的类。我们可以使用extends
告诉编译器一些关于T
的信息,但是在Java中,我们无法指定T
有一个构造函数T(byte[])
(或者无论recordDelimiterBytes
的类型是什么)
我已经多次使用下面的解决方案,尽管它需要创建子类,但我对它非常满意。这项工作仍在泛型类中。现在宣布为抽象:
public abstract class InputFormat<T extends RecordReader<NullWritable, LegionRecord>>
extends FileInputFormat<NullWritable, LegionRecord> {
private byte[] recordDelimiterBytes;
@Override
public RecordReader<NullWritable, LegionRecord> createRecordReader(InputSplit split, TaskAttemptContext context) {
/* Skipped code for getting recordDelimiterBytes */
return constructRecordReader(recordDelimiterBytes);
}
// factory method for T objects
protected abstract RecordReader<NullWritable, LegionRecord> constructRecordReader(byte[] recordDelimiterBytes);
}
然后,您只需在实施过程中跟进:
protected LegionRecordReader constructRecordReader(byte[] recordDelimiterBytes) {
在这种情况下,它甚至会缩短几个字符。另一方面,在您的情况下,您似乎不需要它,因此您可能更喜欢使用较弱的返回类型
RecordReader
。不过,我不确定为什么这会阻止这种情况发生?因此,在编译时,T
被LegionRecordReader
或任何其他RecordReader
类I指定的。。。为什么这会阻止returnnewt
在编译时变成returnnewlegionrecordreader
?在编译时,T
被java.lang.Object
取代。不是LegionRecordReader
。编译器无法知道T
是否有一个接受recordDelimiterBytes
作为参数的构造函数