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

发布于 2024-11-29 19:47:18 字数 1474 浏览 2 评论 0原文

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

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

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

此致。

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

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

蓝颜夕 2024-12-06 19:47:18

新想法

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

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 的 commons lang 的帮助程序类。

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.

夏末的微笑 2024-12-06 19:47:18

我不确定您的过滤器将如何工作,因为它不知道有关数组包含的类型的任何信息。

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

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

Array.get() 函数将返回所请求的数组索引处的值,如果它是基元,则将其包装在其相应的对象类型中。缺点是您必须更改方法签名以接受 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
        }
    }
}

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

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.

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.

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.

无声情话 2024-12-06 19:47:18
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);
        ...
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);
        ...
凉城凉梦凉人心 2024-12-06 19:47:18

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

    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
    }

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
    }
从来不烧饼 2024-12-06 19:47:18
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

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

饮惑 2024-12-06 19:47:18

你可以做这样的事情。

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

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

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.

仄言 2024-12-06 19:47:18

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

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.

听风吹 2024-12-06 19:47:18

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

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

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.


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:

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;
}
回心转意 2024-12-06 19:47:18

不,这是不可能的。

例如,查看

此外,我们可以更多地讨论泛型的工作原理,但我想这将是另一个问题。

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.

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

旧时浪漫 2024-12-06 19:47:18

取决于您想要实现的目标。但也许您可以使用原始包装器?然后你可以编写通用的Extractor (这里 Number 是由所有原始包装器扩展的抽象类)。

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 Number is the abstract class extended by all primitive wrappers).

情魔剑神 2024-12-06 19:47:18

是的,您应该能够使用泛型:

    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 可以是 ByteInteger 等。

Yes, you should be able to use generics:

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

Here, you would have to assume that T is a primitive array, as you cannot use primitives in generic definitions.

Or else, you could use the wrapper Objects and do it this way:

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

In this case, your generic T can be Byte, Integer, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文