簡體   English   中英

使用原始類型時如何避免重復?

[英]How to avoid repetition when working with primitive types?

我需要對各種原始類型執行算法; 算法基本相同,但變量的類型除外。 所以,例如,

/**
* Determine if <code>value</code> is the bitwise OR of elements of <code>validValues</code> array. 
* For instance, our valid choices are 0001, 0010, and 1000.
* We are given a value of 1001.  This is valid because it can be made from
* ORing together 0001 and 1000.
* On the other hand, if we are given a value of 1111, this is invalid because
* you cannot turn on the second bit from left by ORing together those 3
* valid values.
*/
public static boolean isValid(long value, long[] validValues) {
    for (long validOption : validValues) {
        value &= ~validOption;
    }
    return value == 0;
}

public static boolean isValid(int value, int[] validValues) {
    for (int validOption : validValues) {
        value &= ~validOption;
    }
    return value == 0;
}

我怎樣才能避免這種重復? 我知道沒有辦法對原始數組進行泛化,所以我的雙手似乎很緊張。 我有原始數組的實例,而不是說Number對象的盒裝數組,所以我也不想去那條路。

我知道有很多關於數組,自動裝箱等原語的問題,但我還沒有看到它以這種方式制定,我還沒有看到如何與這些數組交互的決定性答案。

我想我可以這樣做:

public static<E extends Number> boolean isValid(E value, List<E> numbers) {
    long theValue = value.longValue();
    for (Number validOption : numbers) {
        theValue &= ~validOption.longValue();
    }
    return theValue == 0;
}

然后

public static boolean isValid(long value, long[] validValues) {
    return isValid(value, Arrays.asList(ArrayUtils.toObject(validValues)));
}

public static boolean isValid(int value, int[] validValues) {
    return isValid(value, Arrays.asList(ArrayUtils.toObject(validValues)));
}

這真的好多了嗎? 這種方式將創建比原始實現更多的對象,盡管它會干掉源代碼。 對此事的任何想法都將不勝感激。

我之前問了一個類似的問題( 在Java中管理高度重復的代碼和文檔 ),並注意到java.util.Arrays的源代碼在其處理原始數組類型的算法java.util.Arrays高度重復的

實際上,源代碼包含以下注釋:

七種原始類型中的每一種的代碼大致相同。 這就是生活。

我接受的答案建議使用代碼生成器,讓您使用代碼模板。 還有一條評論稱Sun / Oracle內部也使用了模板系統。

你也可以使用反射來減少重復,但這可能很慢,也許不值得努力。 如果您想測試其性能,此片段演示了該技術:

import java.lang.reflect.Array;

static long maskFor(Class<?> c) {
    return (
        c.equals(int.class) ? 1L << Integer.SIZE :
        c.equals(short.class) ? 1L << Short.SIZE :
        c.equals(byte.class) ? 1L << Byte.SIZE :
        0
    ) - 1;
}   
public static void reflectPrimitiveNumericArray(Object arr) throws Exception {
    int length = Array.getLength(arr);
    Class<?> componentType = arr.getClass().getComponentType();
    long mask = maskFor(componentType);
    System.out.format("%s[%d] = { ", componentType, length);
    for (int i = 0; i < length; i++) {
        long el = Array.getLong(arr, i) & mask;
        System.out.print(Long.toBinaryString(el) + " ");
    }
    System.out.println("}");
}

您可以為arr以及其他原始數組類型傳遞int[] 一切都被投入long ,通過位屏蔽來解決符號擴展問題。

reflectPrimitiveNumericArray(new byte[] { (byte) 0xF0 });
// byte[1] = { 11110000 }
reflectPrimitiveNumericArray(new int[] { 0xF0F0F0F0 });
// int[1] = { 11110000111100001111000011110000 }
reflectPrimitiveNumericArray(new long[] { 0xF0F0F0F0F0F0F0F0L });
// long[1] = { 1111000011110000111100001111000011110000111100001111000011110000 }

如果你查看java.util.Arrays ,你會發現即使他們必須為每種基本類型專門化他們的所有算法( binarySearchequals等)。

如果性能是一個問題,我不建議依賴自動裝箱,但如果不是(在您進行了分析之后),它將是一個有效的選項。

我覺得你很害怕 - 我沒有離開原始類型。

在以前的生活中,我們有一些原始類型的集合,這些集合針對財務數據進行了優化(內存中有數百萬個訂單,使用分塊數組等)。 我們的解決方案很像Trove,有一些存根文件。 例如,'原始'源文件會說... HashSet_key。 對於值的一些存根類,我們遵循Trove的使用ant任務的模型來生成HashSetInt,HashSetLong等...

我一直認為這是一種“笨拙”的方法,但它有效。 我很好奇有人曾經嘗試過Velocity,或者可能是FMPP,並且有一些稍微清潔的結果嗎? 我對ant解決方案的主要問題是所有代碼都非常接近,而在很多源代碼生成中,您可以更好地分離模板文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM