java 原始数组的“通用”解决方案?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7041636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 18:25:48  来源:igfitidea点击:

"Generic" solution for primitive array?

javaarraysrefactoringprimitive-types

提问by Genzer

I have classes that for processing primitive array input: CharArrayExtractor for char[], ByteArrayExtractor for byte[], IntegerArrayExtractor for int[], ...

我有用于处理原始数组输入的类:用于 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.
    }
}

The problem here is that the algorithm for extracting the data is the same, only the types of input are different. Everytime the algorithm changes, I have to change all of the extractor classes.

这里的问题是提取数据的算法是一样的,只是输入的类型不同。每次算法更改时,我都必须更改所有提取器类。

Is there a way to make extractor classes more "generics"?

有没有办法让提取器类更“泛型”?

Best regards.

最好的祝福。

EDIT: It seems that every suggestion so far is to use autoboxing to archive generic. But the number of elements of the array is often large, so I avoid using autoboxing.

编辑:到目前为止,似乎每个建议都是使用自动装箱来归档泛型。但是数组的元素数量通常很大,所以我避免使用自动装箱。

I added more specific implementation of how the data is being extracted. Hope it will clarify something.

我添加了更多关于如何提取数据的具体实现。希望它会澄清一些事情。

采纳答案by rit

New Idea

新想法

Or a different approach is wrapping the primitive arrays and covering them with the methods you use for your algorithm.

或者另一种方法是包装原始数组并用您用于算法的方法覆盖它们。

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");
        ...
    }
}

This mainly depends if you have a lot of methods to call which you would have to cover. but at least you must not edit the algorithm more over the way how to access the primitive array. Furthermor you would also be able to use a different object inside the wrapper.

这主要取决于您是否有很多方法可以调用,而这些方法必须涵盖。但至少你不能在如何访问原始数组的方式上编辑算法。此外,您还可以在包装器内使用不同的对象。

Old Idea

旧想法

Either use generics or what i also think about is to have three methods which convert the primitive types into value types.

要么使用泛型,要么我也想到的是拥有三种将原始类型转换为值类型的方法。

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 is a helper class from commons lang from Apache.

ArrayUtils 是来自 Apache 的 commons lang 的辅助类。

回答by irreputable

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);
        ...

回答by Aaron

I'm not sure how your filter will work as it will not know anything about the type the array contains.

我不确定您的过滤器将如何工作,因为它对数组包含的类型一无所知。

Using reflection you can possibly do what you want but you will loose compile time type safety.

使用反射你可以做你想做的事,但你会失去编译时的类型安全性。

The java.lang.reflect.Array class provides functions for manipulating an array without knowing its type.

java.lang.reflect.Array 类提供了在不知道数组类型的情况下操作数组的函数。

The Array.get()function will return the value at the requested index of the array and if it is a primitive wrap it in its corresponding Object type. The downside is you have to change your method signature to accept Object instead of specific array types which means the compiler can no longer check the input parameters for you.

所述Array.get()函数将所述阵列的所述请求的索引处返回值,如果它是一个原始涡卷在其对应的对象类型。缺点是您必须更改方法签名以接受 Object 而不是特定的数组类型,这意味着编译器无法再为您检查输入参数。

Your code would become:

你的代码会变成:

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
        }
    }
}

Personally I would prefer having type safety over using reflection even if it is a little more verbose.

就我个人而言,我更喜欢使用类型安全而不是使用反射,即使它有点冗长。

回答by Kowser

No, it is never possible.

不,永远不可能。

For example take a look at documentation of ArrayUtils.copyOf(byte[] original, int newLength). And there exists other methods for remaining primitives. This is kind of same behavior (literally) you wanted. If it was possible similar code should exists somewhere else.

例如,看看ArrayUtils.copyOf(byte[] original, int newLength) 的文档。并且存在用于剩余基元的其他方法。这与您想要的行为(字面意思)相同。如果可能的话,类似的代码应该存在于其他地方。

Additionally we can discuss more about how generic works, but it would be another issue, i guess.

此外,我们可以讨论更多关于泛型如何工作的问题,但我想这将是另一个问题。

回答by jFrenetic

Depends on what you're trying to achieve. But maybe you can work with primitive wrappers instead? Then you could write generic Extractor<? extends Number>(here Numberis the abstract class extended by all primitive wrappers).

取决于你想要达到的目标。但也许你可以使用原始包装器来代替?然后你可以编写泛型Extractor<? extends Number>(这里Number是由所有原始包装器扩展的抽象类)。

回答by Suraj Chandran

Instead of passing each type, pass the class of the type as the below:

不是传递每种类型,而是传递类型的类,如下所示:

    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
    }

回答by Kevin Bowersox

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

http://download.oracle.com/javase/tutorial/extra/generics/methods.html

回答by SirPyros

You could do something like this.

你可以做这样的事情。

public class ArrayExtractor<T>
{
    public List<T> extract (T[] source)
    {
        // filter and extract data from the array.
    }
}

You would have a generic Extractor class and your implementation would be the same.

您将拥有一个通用的 Extractor 类,并且您的实现将是相同的。

回答by Martijn Courteaux

I think is is possible to do create a method like this:

我认为可以创建这样的方法:

public List<Record> extract(List<Number> source) {
    // filter and extract data from the array.
}

And use Arrays.asList(yourPrimaryArrayType), to make it compatible.

并使用Arrays.asList(yourPrimaryArrayType), 使其兼容。



After my tests and the comment of Sean Patrick Floyd, you will be able to do this by create once some helper methods, for converting primitive arrays to lists:

在我的测试和Sean Patrick Floyd的评论之后,您将能够通过 create once 一些辅助方法来做到这一点,用于将原始数组转换为列表:

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;
}

回答by Michele

You cant use Javas generics because of primitive type source, your best bet is to try some java reflection api to analyze the incoming source and invoke the extractors on your own.

由于原始类型源,您不能使用 Java 泛型,最好的办法是尝试一些 Java 反射 api 来分析传入的源并自行调用提取器。