我有用于处理原始数组输入的类:char []的CharArrayExtractor,byte []的ByteArrayExtractor,int []的IntegerArrayExtractor,...
public void CharArrayExtractor {
public List<Record> extract(char[] source) {
List<Record> records = new ArrayList<Record>();
int recordStartFlagPos = -1;
int recordEndFlagPos = -1;
for (int i = 0; i < source.length; i++) {
if (source[i] == RECORD_START_FLAG) {
recordStartFlagPos = i;
} else if (source[i] == RECORD_END_FLAG) {
recordEndFlagPos = i;
}
if (recordStartFlagPos != -1 && recordEndFlagPos != -1) {
Record newRecord = makeRecord(source, recordStartFlagPos,
recordEndFlagPos);
records.add(newRecord);
recordStartFlagPos = -1;
recordEngFlagPos = -1;
}
}
}
}
public void ByteArrayExtractor {
public List<Record> extract(byte[] source) {
// filter and extract data from the array.
}
}
public void IntegerArrayExtractor {
public List<Record> extract(int[] source) {
// filter and extract data from the array.
}
}
这里的问题是提取数据的算法是相同的,只有输入的类型是不同的。每次算法更改时,我都必须更改所有提取器类。
有没有办法让提取器类更“泛型”?
最好的问候。
编辑:到目前为止,似乎每个建议都是使用自动装箱来归档通用。但是阵列的元素数量通常很大,所以我避免使用自动装箱。
我添加了更具体的数据提取方式。希望它能澄清一些事情。
答案 0 :(得分:3)
新主意
或者另一种方法是包装原始数组并使用您用于算法的方法覆盖它们。
public PrimitiveArrayWrapper {
private byte[] byteArray = null;
private int[] intArray = null;
...
public PrimitiveArrayWrapper(byte[] byteArray) {
this.byteArray = byteArray;
}
// other constructors
public String extractFoo1(String pattern) {
if(byteArray != null) {
// do action on byteArray
} else if(....)
...
}
}
public class AlgorithmExtractor {
public List<Record> do(PrimitiveArrayWrapper wrapper) {
String s= wrapper.extractFoo1("abcd");
...
}
}
这主要取决于你有很多方法要调用,你需要覆盖。但至少你不能在如何访问原始数组的方式上编辑算法。此外,您还可以在包装器中使用不同的对象。
旧观念
使用泛型或者我也想到的是有三种方法将原始类型转换为值类型。
public void Extractor {
public List<Record> extract(byte[] data) {
InternalExtractor<Byte> ie = new InternalExtractor<Byte>();
return ie.internalExtract(ArrayUtils.toObject(data));
}
public List<Record> extract(int[] data) {
...
}
}
public void InternalExtractor<T> {
private List<Record> internalExtract(T[] data) {
// do the extraction
}
}
ArrayUtils是来自Apache的公共资源的助手类。
答案 1 :(得分:2)
interface Source
int length();
int get(int index);
extract(final byte[] source)
extract( new Source(){
int length(){ return source.length; }
int get(int i){ return source[i]; }
} );
// common algorithm
extract(Source source)
for(int i=0; i<source.lenth(); i++)
int data = source.get(i);
...
答案 2 :(得分:2)
我不确定你的过滤器是如何工作的,因为它不知道数组包含的类型。
使用反射你可以做你想做的事,但是你会失去编译时类型的安全性。
java.lang.reflect.Array类提供了在不知道其类型的情况下操作数组的函数。
Array.get()函数将返回所请求的数组索引处的值,如果是原语,则将其包装在相应的Object类型中。缺点是您必须更改方法签名以接受Object而不是特定的数组类型,这意味着编译器无法再为您检查输入参数。
您的代码将变为:
public class ArrayExtractor {
public List<Record> extract(Object array) {
// filter and extract data from the array.
int length = Array.getLength(array);
for (int index = 0; index < length; index++) {
Object value = Array.get(array, index);
// somehow filter using value here
}
}
}
就我个人而言,我宁愿使用反射来保证类型安全,即使它更加冗长。
答案 3 :(得分:0)
取决于你想要达到的目标。但也许你可以使用原始包装器呢?然后你可以编写泛型Extractor<? extends Number>
(这里Number
是所有原始包装器扩展的抽象类)。
答案 4 :(得分:0)
不是传递每种类型,而是传递类型的类,如下所示:
public List<Record> extract(Class srcClass) {
if (int[].class.equals(srcClass) {
// filter and extract data from the int[] array.
}
else if (..) // do same for other types
}
答案 5 :(得分:0)
public void Extractor<T> {
public List<Record> extract(T[] source) {
// filter and extract data from the array.
}
}
http://download.oracle.com/javase/tutorial/extra/generics/methods.html
答案 6 :(得分:0)
你可以这样做。
public class ArrayExtractor<T>
{
public List<T> extract (T[] source)
{
// filter and extract data from the array.
}
}
您将拥有一个通用的Extractor类,您的实现将是相同的。
答案 7 :(得分:0)
我认为可以创建这样的方法:
public List<Record> extract(List<Number> source) {
// filter and extract data from the array.
}
并使用Arrays.asList(yourPrimaryArrayType)
,使其兼容。
在我的测试和 Sean Patrick Floyd 的评论之后,你可以通过创建一些辅助方法来实现这一点,将原始数组转换为列表:
public static void main(String[] args)
{
int[] i = {1,2,3};
System.out.println(extract(asPrimitiveList(i)));
}
public static List<Object> extract(List<Number> source) {
List<Object> l = new ArrayList<Object>();
l.add(0);
for (Number n : source)
{
// I know this line is rubbish :D
l.set(0, ((Number) l.get(0)).doubleValue() + n.doubleValue());
}
return l;
}
private static List<Number> asPrimitiveList(int[] ia)
{
List<Number> l = new ArrayList<Number>(ia.length);
for (int i = 0; i < ia.length; ++i)
{
l.add(ia[i]);
}
return l;
}
private static List<Number> asPrimitiveList(byte[] ia)
{
List<Number> l = new ArrayList<Number>(ia.length);
for (int i = 0; i < ia.length; ++i)
{
l.add(ia[i]);
}
return l;
}
private static List<Number> asPrimitiveList(char[] ia)
{
List<Number> l = new ArrayList<Number>(ia.length);
for (int i = 0; i < ia.length; ++i)
{
l.add(ia[i]);
}
return l;
}
答案 8 :(得分:0)
由于原始类型的源代码,您不能使用Java泛型,最好的办法是尝试使用一些java反射API来分析传入的源并自行调用提取器。
答案 9 :(得分:0)
不,永远不可能。
例如,请查看ArrayUtils.copyOf(byte[] original, int newLength)的文档。并且存在用于保留基元的其他方法。这是你想要的一种相同的行为(字面意思)。如果有可能类似的代码应该存在于其他地方。
此外,我们可以讨论更多关于通用的工作原理,但我认为这将是另一个问题。
答案 10 :(得分:-1)
是的,您应该能够使用泛型:
interface Extractor<T, R> {
public List<R> extract(T source);
}
class BaseExtractor<T> implements Extractor<T, Record>
{
public List<Record> extract(T source)
{
//do your thing
}
}
在这里,你必须假设T
是一个原始数组,因为你不能在泛型定义中使用原语。
或者,您可以使用包装器对象并以这种方式执行:
interface Extractor<T, R> {
public List<R> extract(T[] source);
}
class BaseExtractor<T> implements Extractor<T, Record>
{
public List<Record> extract(T[] source)
{
//do your thing
}
}
在这种情况下,您的通用T
可以是Byte
,Integer
等。